大数跨境
0
0

AI 赋能广告采集与监测:自动化系统设计与实践

AI 赋能广告采集与监测:自动化系统设计与实践 搜狐技术产品
2025-12-03
2


01

一、项目背景与整体架构

在做广告监测自动化之前,最先遇到的痛点就是人工监测效率极低。开发这套系统的过程,更多像是一场不断平衡"准确性、性能、跨设备兼容性"的技术实践。

在移动广告监测领域,自动化、高效、可靠的广告识别与采集系统对于广告效果评估、竞品分析以及广告合规性检测至关重要。随着移动应用生态的快速发展,传统的人工监测方式已无法满足大规模、高频次、多维度的广告数据采集需求。该项目——Android广告监测系统,旨在解决这一痛点。整个系统并非一开始就成型,而是在多次迭代中逐步演进,通过不断踩坑和取舍才最终沉淀下来。

1.1 项目概述

Android广告监测系统是一套集设备控制、应用自动化操作、广告识别、数据采集与状态监控于一体的完整解决方案。该系统能够同时控制多台Android设备,自动启动指定应用,检测并截图开屏广告和信息流广告,通过OCR技术识别广告内容,并将结果实时上传至服务器。同时,系统提供了直观的状态监控机制,让操作人员能够实时了解各设备的工作状态。

1.2 系统架构设计

整个系统采用分层设计架构,主要包括以下几个核心层次:

  1. 设备控制层:负责与Android设备建立连接,执行设备级操作(如唤醒、解锁、启动应用等)

  2. 应用自动化层:实现应用内部的自动化操作,如滑动、点击、切换频道等

  3. 广告识别层:通过OCR技术对截图进行文字识别,结合关键词匹配算法判断是否为广告

  4. 数据采集与传输层:负责截图的保存、上传以及状态信息的传递

  5. 监控展示层:以Android悬浮窗形式实时展示各设备的工作状态

这种分层设计使得系统各模块之间职责清晰,耦合度低,便于维护和扩展。系统整体架构如下图所示:

02

二、核心功能模块实现

2.1 设备管理与多进程并发控制

在广告监测场景中,同时控制多台设备进行并行监测是提升效率的关键。本系统通过Python的multiprocessing模块实现多设备的并发控制,确保每台设备都能独立执行广告监测任务,互不干扰。

系统提供了三种启动模式,以适应不同的设备配置需求:

• 全部设备模式 (main.py):自动检测所有已连接的Android设备,并为每台设备创建独立进程执行监测任务

• 单设备模式 (main一台.py):仅在指定的单台设备上执行监测任务

• 多设备排除模式 (main两台.py):在除指定设备外的所有设备上执行监测任务

这种灵活的启动模式设计,使得操作人员可以根据实际需求和设备资源情况,灵活选择适合的运行策略。

设备管理的核心代码实现如下:


     
      
     # === 启动入口:多设备并发执行 ===
if __name__ == "__main__":

    # 获取所有已连接的设备
    all_devices = utils.get_connected_devices()
    if not all_devices:
        print("❌ 未检测到任何物理设备")
        exit(1)

    # 为每台设备创建独立进程
    processes = []
    for device_id in all_devices:
        p = Process(target=ad_monitor.run_on_device, args=(device_id,))
        p.start()
        processes.append(p)

    # 等待所有进程完成
    for p in processes:
        p.join()

这种基于多进程的并发控制方式,相比多线程方案具有明显优势,特别是在涉及到大量I/O操作和第三方库调用的场景下。每个进程都拥有独立的Python解释器和内存空间,避免了多线程中的GIL(全局解释器锁)限制,同时也降低了进程间的干扰风险,提高了系统的稳定性。

2.2 设备控制与应用自动化

设备控制与应用自动化是整个监测流程的基础。系统通过ADB(Android Debug Bridge)与设备进行通信,实现设备唤醒、解锁、应用启动、切换等操作。同时,结合uiautomator2库,实现更精细的应用内部操作控制。

设备控制的核心功能主要包括:

  1. 设备连接管理:检测已连接设备,建立ADB通信通道

  2. 设备状态控制:实现设备的唤醒、解锁、锁屏等基础操作

  3. 应用生命周期管理:实现应用的安装检查、启动、关闭等操作

  4. 屏幕操作模拟:实现屏幕滑动、点击等操作,模拟用户行为

以设备唤醒和解锁功能为例,其实现代码如下:


     
      
     # === 设备操作相关方法 ===
def wake_and_unlock(device_id):
    # 发送电源键事件唤醒设备
    subprocess.run(["adb", "-s", device_id, "shell", "input", "keyevent", "224"])
    # 解除屏幕锁定
    subprocess.run(["adb", "-s", device_id, "shell", "wm", "dismiss-keyguard"])


def lock_screen(device_id):
    # 发送电源键事件锁定屏幕
    subprocess.run(["adb", "-s", device_id, "shell", "input", "keyevent", "26"], stdout=subprocess.DEVNULL)

为了实现更复杂的应用内操作,系统集成了uiautomator2库,该库提供了更高级的UI交互能力。以滑动操作为例:


     
      
     def scroll_half_screen(device):
    try:
        # 获取屏幕尺寸
        size = device.window_size()
        # 计算滑动起始点和终点
        start_x = size[0] // 2
        start_y = size[1] * 3 // 4
        end_y = size[1] // 4
        # 执行滑动操作,持续时间0.2秒
        device.swipe(start_x, start_y, start_x, end_y, 0.2)
        time.sleep(1)
    except Exception as e:
        print(f"⚠️ 滑动失败:{e}")

通过这种组合方式,系统能够高效地控制设备并模拟用户操作,为广告检测提供了坚实的基础。

2.3 广告识别与OCR技术应用

广告识别是系统的核心功能之一,直接决定了监测的准确性和效率。系统采用了基于OCR(光学字符识别)技术与关键词匹配相结合的广告识别方案。

广告识别的工作流程如下:

  1.  对设备屏幕进行截图,保存为临时文件

  2. 使用OCR技术提取截图中的文字内容

  3. 将提取的文字与预定义的广告关键词库进行比对

  4. 根据比对结果判断是否为广告,并记录识别到的关键词

系统支持两种主要的广告类型识别:

• 开屏广告识别:主要识别包含"跳过"、"Skip"等关键词的广告

• 信息流广告识别:主要识别包含"广告"等关键词的内容

广告识别的核心代码实现如下:


     
      
     # === OCR识别函数:检查图片中是否包含广告关键词 ===
def ocr_detect_ad(image_path, keywords):
    try:
        # 使用OCR引擎识别图片中的文字
        text = fuOCR.getTextFromImage(image_path)

        # 检查是否包含广告关键词
        for keyword in keywords:
            if keyword in str(text):
                return True, keyword, str(text)
        return False, None, None
    except Exception as e:
        print(f"⚠️ OCR识别失败:{e}")
        return False, None, None

开屏广告检测的具体实现如下:


     
      
     # === 开屏广告检测函数 ===
def capture_splash_ad(device, app_name, save_dir, i, log_file, device_id):
    # 生成带时间戳的临时文件路径
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    temp_filepath = os.path.join(save_dir, f"{app_name}_splash_temp_{timestamp}_{i+1}.png")
    log_message(log_file, f"📸 截图保存:{temp_filepath}")
    # 执行屏幕截图
    device.screenshot(temp_filepath)

    # 使用OCR技术检测开屏广告
    is_ad, keyword, txt = ocr_detect_ad(temp_filepath, config.SPLASH_AD_KEYWORDS)

    if is_ad:
        # 打印OCR识别内容
        log_message(log_file, f"🔍 OCR识别内容: {txt}")

        # 发送发现广告状态
        notify_status(device_id, "found_ad", f"发现 {app_name} 开屏AD")

        # 上传并删除临时截图
        upload_and_delete(temp_filepath, {
            "media": app_name, "position_type": "开屏", "os": "Android", "detected_keyword": keyword
        }, log_file)
        log_message(log_file, f"✅ 检测到开屏广告(关键词: {keyword})(第 {i+1} 次)")
        return True  # 检测到广告返回True
    else:
        log_message(log_file,f"⚠️ 未检测到开屏广告(第 {i+1} 次)")
        try:
            os.remove(temp_filepath)
        except Exception as e:
            log_message(log_file, f"⚠️ 删除非广告临时截图失败:{e}")
        return False  # 未检测到广告返回False

信息流广告检测则更为复杂,需要模拟用户滑动操作,并对每个页面进行截图和识别。系统实现频道切换功能,可以在不同频道下检测广告,提高了广告发现的覆盖率。

2.4 数据流管理与文件系统设计

系统在运行过程中会产生大量的截图文件和日志记录,因此合理的文件系统设计对于数据管理至关重要。系统采用了分层的文件存储结构,按设备型号和时间进行组织,确保数据的有序存储和高效检索。

文件系统结构如下:

• 日志目录:按设备型号分类存储日志文件

• 截图目录:按设备型号和应用名称分类存储广告截图

• 临时目录:存储过程中产生的临时文件

系统还实现自动清理机制,定期删除超过保留期限的旧日志和截图,避免存储空间过度占用。这对于长期运行的监测系统尤为重要。

文件管理的核心代码实现如下:


     
      
     # 路径配置
import os
# 获取当前脚本所在目录的绝对路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
LOG_DIR = os.path.join(BASE_DIR, "./Android_log")
SAVE_ROOT = os.path.join(BASE_DIR, "./Android_screenshort")
TEMP_DIR = os.path.join(SAVE_ROOT, "temp")  # 临时截图目录

# 设置日志和截图保留时长
RETENTION_TIME = timedelta(days=2)   # 正式环境用
2.5 状态监控与跨进程通信

状态监控是系统的重要组成部分,能够让操作人员实时了解各设备的工作状态。系统实现一套完整的状态通信机制,由Python监测脚本和Android悬浮窗应用两部分组成。

在最初的设计中,系统采用了Socket通信方式,但在实际运行中发现,在低端Windows设备上存在丢包和卡顿问题。经过深入分析和优化,系统最终采用了ADB广播为主、Socket通信为备份的混合通信方案,显著提升了在低端设备上的性能和稳定性。

03

三、跨进程通信技术深度解析

3.1 通信需求分析与技术选型

在Android广告监测系统中,跨进程通信是连接Python监测脚本和Android悬浮窗应用的关键环节。系统需要实时、可靠地传递设备状态信息,包括:

• 设备空闲状态

• 广告检测中状态

• 发现广告状态

• 广告上传中状态

• 任务完成状态

• 错误状态

针对这些需求,我们评估了多种跨进程通信技术方案。下表详细对比了不同通信方案的特点和适用场景:

通信方案 实现方式 优点 缺点 适用场景
Socket通信
基于TCP/IP协议,通过端口转发实现PC与设备间通信
1. 跨平台兼容性好
2. 实现简单直观
3. 支持双向通信
1. 在低端设备上性能开销大
2. 短连接频繁创建/销毁资源浪费
3. 缺乏消息确认机制
4. 端口转发增加延迟和复杂性
开发调试阶段、高端设备环境
Windows命名管道
利用Windows操作系统提供的命名管道机制
1. Windows平台下性能优秀
2. 支持消息队列和异步操作
3. 安全性较高
1. 仅适用于Windows平台
2. 实现相对复杂
3. 不支持跨设备通信
Windows平台专用应用
消息队列
基于内存或文件的消息队列实现
1. 解耦发送方和接收方
2. 支持异步处理
3. 可缓冲消息峰值
1. 需要额外的队列管理逻辑
2. 跨设备通信复杂
3. 可能存在消息丢失风险
单设备多进程间通信
ADB广播通信
利用Android系统的广播机制,通过ADB命令发送广播
1. 直接利用Android系统机制
2. 无需额外端口转发
3. 资源占用低,适合低端设备
4. 实现简单可靠
1. 仅适用于Android设备
2. 消息长度有限制
3. 不支持双向通信
Android设备与PC间通信

经过详细对比和实际测试,我们发现ADB广播通信在Android设备监测场景下具有显著优势,特别是对于低端Windows设备。下面将深入分析ADB广播通信的原理和实现细节。

3.2 ADB广播通信原理与实现

ADB(Android Debug Bridge)是Android开发工具包中的一个命令行工具,用于与Android设备进行通信。ADB广播通信是利用ADB命令向Android设备发送系统广播,然后在设备端注册广播接收器来接收和处理这些广播。

3.2.1 ADB广播通信的工作原理

ADB广播通信的基本工作流程如下:

  1. PC端发送广播:通过adb shell am broadcast命令向Android设备发送自定义广播

  2. 设备端接收广播:在Android应用中注册广播接收器,监听特定的广播Intent

  3. 处理广播消息:接收到广播后,解析消息内容并执行相应的操作

与Socket通信相比,ADB广播通信具有以下技术优势:

• 无需端口转发:Socket通信需要通过adb forward命令设置端口转发,增加了系统复杂性和延迟

• 资源占用低:ADB广播直接利用Android系统的广播机制,无需维护TCP连接

• 实现简单可靠:不需要处理复杂的网络连接管理、异常处理等问题

• 兼容性好:在各种配置的设备上都能稳定运行,特别适合低端设备

3.2.2 广播通信的实现细节

在Python端,我们实现notify_status函数,用于向设备发送状态广播:


     
      
     # === 发送状态通知 ===
def notify_status(device_id, status, message):
    try:
        # 构造状态消息
        status_message = f"STATUS|{device_id}|{status}|{message}"

        # 首先尝试使用ADB广播发送状态
        broadcast_cmd = ["adb", "-s", device_id, "shell", 
                        "am", "broadcast", 
                        "-a", "com.monitor.statuswindow.UPDATE_STATUS", 
                        "--es", "message", status_message]

        result = subprocess.run(broadcast_cmd, capture_output=True, text=True)

        # 检查ADB广播是否成功发送
        if "Broadcasting: Intent" in result.stdout:
            print(f"✅ 已发送状态广播:{status_message}")
            return True
        else:
            # ADB广播发送失败,降级使用Socket通信
            print(f"⚠️ ADB广播发送失败,尝试使用Socket通信")

            # Socket通信实现(降级方案)
            try:
                # 创建Socket连接
                with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                    s.settimeout(1)
                    # 连接到设备的8888端口
                    s.connect(("localhost", 8888))
                    # 发送状态消息
                    s.sendall(status_message.encode('utf-8'))
                print(f"✅ 已发送Socket消息:{status_message}")
                return True
            except Exception as e:
                print(f"❌ 状态发送失败:{e}")
                return False
    except Exception as e:
        print(f"❌ 状态发送异常:{e}")
        return False

在Android端,创建StatusBroadcastReceiver类来接收和处理状态广播:


     
      
     package com.monitor.statuswindow

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log

class StatusBroadcastReceiver(private val statusListener: StatusServer.StatusListener) : BroadcastReceiver() {
    private val TAG = "StatusBroadcastReceiver"

    override fun onReceive(context: Context?, intent: Intent?) {
        // 检查广播Action是否匹配
        if (intent?.action == "com.monitor.statuswindow.UPDATE_STATUS") {
     ...

04

四、Android悬浮窗监控系统设计

Android悬浮窗是整个广告监测系统的重要组成部分,为操作人员提供了直观、实时的状态监控界面。本节将详细介绍悬浮窗的设计理念、实现细节以及技术难点的解决方案。

4.1 悬浮窗设计理念与功能规划

悬浮窗设计的核心目标是提供一种不干扰设备正常运行,但又能实时展示监测状态的界面。主要功能包括:

  1. 实时状态显示:以不同颜色和图标直观展示当前设备的工作状态

  2. 设备标识:显示当前设备的ID,方便多设备场景下的区分

  3. 详细信息:展示当前的操作内容、广告发现情况等详细信息

  4. 交互支持:支持拖动移动位置,点击可打开主界面

为了实现这些功能,系统采用了Service+WindowManager的架构,结合前台服务确保在Android系统后台限制下仍能稳定运行。

4.2 WindowManager实现细节

WindowManager是Android系统提供的窗口管理服务,负责管理应用窗口的创建、显示、隐藏等操作。在悬浮窗实现中,WindowManager的正确配置是关键。

4.2.1 悬浮窗参数配置


     
      
     private fun initFloatingView() {
    // 获取WindowManager服务
    windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager

    // 加载悬浮窗布局
    floatingView = LayoutInflater.from(this).inflate(R.layout.floating_window, null)

    // 设置悬浮窗参数
    val layoutParams = WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            WindowManager.LayoutParams.TYPE_PHONE
        },
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT
    )

    // 设置悬浮窗的初始位置
    layoutParams.gravity = Gravity.TOP or Gravity.START
    layoutParams.x = 0
    layoutParams.y = 100

    // ... 添加触摸事件和悬浮窗到WindowManager
}

在这段代码中,有几个关键参数需要特别注意:

  1. 窗口类型设置

    • 对于Android 8.0(API 26)及以上版本,必须使用TYPE_APPLICATION_OVERLAY类型

    •  对于Android 8.0以下版本,使用TYPE_PHONE类型
      这是因为Android 8.0引入了更严格的悬浮窗权限管理机制,必须使用新的窗口类型

  2. 窗口标志

    • FLAG_NOT_FOCUSABLE:确保悬浮窗不会获取焦点,不影响用户对其他应用的操作

  3. 窗口大小

    • 使用WindowManager.LayoutParams.WRAP_CONTENT确保悬浮窗根据内容自动调整大小

  4.  像素格式

    • PixelFormat.TRANSLUCENT允许悬浮窗具有透明效果,提升视觉体验

4.2.2 悬浮窗添加与管理


     
      
     // 添加悬浮窗到WindowManager
windowManager.addView(floatingView, layoutParams)

// 初始状态设置为空闲
updateStatusUI()

// 在服务销毁时移除悬浮窗
override fun onDestroy() {
    super.onDestroy()
    // ... 其他清理操作

    // 移除悬浮窗
    try {
        if (::windowManager.isInitialized && ::floatingView.isInitialized) {
            windowManager.removeView(floatingView)
        }
    } catch (e: Exception) {
        Log.e("FloatingService", "移除悬浮窗失败: ${e.message}")
    }

    // ... 其他清理操作
}
4.3 悬浮窗交互设计

为了提升用户体验,悬浮窗实现了拖动和点击交互功能:


     
      
     // 为悬浮窗添加触摸事件,实现拖动功能
var lastX = 0
var lastY = 0
var initialX = 0
var initialY = 0

floatingView.setOnTouchListener {
        _, event ->
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            // 获取初始位置
            initialX = event.rawX.toInt()
            initialY = event.rawY.toInt()
            lastX = event.rawX.toInt()
            lastY = event.rawY.toInt()
        }
        MotionEvent.ACTION_MOVE -> {
            // 计算移动距离
            val dx = event.rawX.toInt() - lastX
            val dy = event.rawY.toInt() - lastY

            // 更新悬浮窗位置
            layoutParams.x += dx
            layoutParams.y += dy

            // 应用新位置
            windowManager.updateViewLayout(floatingView, layoutParams)

            lastX = event.rawX.toInt()
            lastY = event.rawY.toInt()
        }
        MotionEvent.ACTION_UP -> {
            // 判断是否为点击事件
            val distanceX = Math.abs(event.rawX.toInt() - initialX)
            val distanceY = Math.abs(event.rawY.toInt() - initialY)
            if (distanceX < 10 && distanceY < 10) {
                // 处理点击事件,例如打开主界面
                val intent = Intent(this, MainActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                startActivity(intent)
            }
        }
    }
    true
}

这段代码实现了两个核心交互功能:

  1. 拖动功能:通过监听ACTION_DOWNACTION_MOVE事件,计算手指移动距离,并通过windowManager.updateViewLayout方法更新悬浮窗位置

  2. 点击功能:在ACTION_UP事件中,判断移动距离是否小于阈值(这里设为10像素),如果是则视为点击事件,打开主界面

4.4 状态更新机制

悬浮窗的核心功能是实时显示设备状态,为此系统实现了完善的状态更新机制:


     
      
     private fun updateStatusUI() {
    // 确保在主线程更新UI
    handler.post {
        try {
            val statusIcon = floatingView.findViewById<ImageView>(R.id.status_icon)
            val statusText = floatingView.findViewById<TextView>(R.id.status_text)
            val background = floatingView.findViewById<View>(R.id.status_background)

            // 根据状态更新UI
            when (currentStatus) {
                "idle" -> {
                    background.setBackgroundResource(R.drawable.status_background_blue)
                    statusIcon.setImageResource(R.drawable.status_idle)
                }
                "detecting" -> {
                    background.setBackgroundResource(R.drawable.status_background_green)
                    statusIcon.setImageResource(R.drawable.status_detecting)
                }
                "found_ad" -> {
                    background.setBackgroundResource(R.drawable.status_background_orange)
                    statusIcon.setImageResource(R.drawable.status_ad_found)
                }
                "uploading" -> {
                    background.setBackgroundResource(R.drawable.status_background_red)
                    statusIcon.setImageResource(R.drawable.status_uploading)
                }
                "completed" -> {
                    background.setBackgroundResource(R.drawable.status_background_gray)
                    statusIcon.setImageResource(R.drawable.status_completed)
                }
                "error" -> {
                    background.setBackgroundResource(R.drawable.status_background_dark_red)
                    statusIcon.setImageResource(R.drawable.status_error)
                }
            }

            // 更新状态文本
            val displayMessage = if (deviceId != null) {
                "$deviceId\n$statusMessage"
            } else {
                statusMessage ?: "等待连接..."
            }
            statusText.text = displayMessage
        } catch (e: Exception) {
            Log.e("FloatingService", "更新UI失败: ${e.message}")
        }
    }
}

系统通过不同的背景颜色和图标直观地表示设备的工作状态,包括:

  • 空闲状态(蓝色):设备处于等待状态

  • 检测中(绿色):正在检测广告

  • 发现广告(橙色):成功识别到广告

  • 上传中(红色):正在上传广告截图

  • 任务完成(灰色):监测任务已完成

  • 错误状态(深红色):发生错误

4.5 Android版本兼容性处理

Android系统对悬浮窗的权限管理在不同版本间有较大差异,系统通过以下方式确保跨版本兼容性:

4.5.1 前台服务适配


     
      
     @SuppressLint("ForegroundServiceType")
override fun onCreate() {
    super.onCreate()
    Log.d("FloatingService", "服务创建")
    handler = Handler(Looper.getMainLooper())

    // 1. 立即创建前台服务通知
    createNotificationChannel()
    val notification = createNotification()
    if (notification != null) {
        startForeground(NOTIFICATION_ID, notification)
    } else {
        Log.e("FloatingService", "创建通知失败,无法启动前台服务")
        stopSelf()
        return
    }

    // ... 其他初始化操作
}

// 启动服务的静态方法
fun startService(context: Context) {
    val intent = Intent(context, FloatingService::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(intent)
    } else {
        context.startService(intent)
    }
}

从Android 8.0开始,系统要求长时间在后台运行的服务必须使用前台服务,并且必须显示通知。系统通过startForegroundServicestartService的版本判断,确保在不同Android版本上都能正确启动服务。

4.5.2 通知通道适配


     
      
     private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            CHANNEL_ID,
            "悬浮窗监控服务",
            NotificationManager.IMPORTANCE_LOW
        )
        channel.description = "用于显示广告监控状态的悬浮窗服务"
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
}

private fun createNotification(): android.app.Notification {
    // ... 构建通知的代码

    val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        android.app.Notification.Builder(this, CHANNEL_ID)
    } else {
        android.app.Notification.Builder(this)
    }

    // ... 设置通知属性的代码

    return builder.build()
}

Android 8.0引入了通知通道机制,要求所有通知必须属于某个通知通道。系统通过版本判断,为Android 8.0及以上版本创建通知通道,确保通知能够正常显示。

05

五、系统调度与工作流设计

5.1 多设备并行处理机制

系统采用了基于Python multiprocessing的多设备并行处理机制,通过为每台设备创建独立的进程,实现高效的并行监测。

系统在启动时,首先检测所有已连接的Android设备,然后为每台设备创建一个进程,执行广告监测任务。进程间相互独立,互不干扰,确保了系统的稳定性和可靠性。

5.2 应用级监测流程

针对每个应用,系统执行一系列自动化操作,完成广告监测任务:

  1. 设备准备:唤醒设备,解除屏幕锁定

  2. 应用启动:启动目标应用

  3. 开屏广告检测:在应用启动后,立即进行截图和OCR识别,检测开屏广告

  4. 信息流广告检测:在应用主界面,模拟用户滑动操作,检测信息流广告

  5. 频道切换:在支持频道切换的应用中,切换到不同频道进行广告检测

  6. 结果处理:识别到广告后,保存截图并上传至服务器

  7. 设备清理:完成任务后,关闭应用并锁定屏幕

每个监测步骤都包含详细的日志记录和状态通知,确保操作人员能够实时了解系统运行情况。

5.3 错误处理与恢复机制

为了提高系统的稳定性和可靠性,系统实现了全面的错误处理与恢复机制:

  1. 超时处理:对每个操作设置超时时间,避免因操作卡住导致整个任务失败

  2. 重试机制:对于可能因网络或设备原因失败的操作,实现自动重试功能

  3. 降级策略:在高级功能(如OCR识别)失败时,尝试使用备选方案完成任务

  4. 异常捕获:对所有可能出现异常的代码块进行异常捕获,确保程序不会因未处理的异常而崩溃

06

六、系统优化与性能调优

6.1 启动流程优化

系统对启动流程进行了全面优化,缩短了系统启动时间,提高了启动成功率。主要优化措施包括:

  1. 设备检测优化:优化设备检测算法,提高设备识别速度和准确性

  2. 资源预加载:预加载OCR模型和常用资源,减少运行时加载时间

  3. 异步初始化:将部分初始化操作改为异步执行,提高启动速度

6.2 内存管理与资源回收

在长时间运行的监测场景中,内存管理和资源回收至关重要。系统采取了多项措施优化内存使用:

  1. 临时文件清理:及时清理不再需要的临时文件,释放存储空间

  2. 资源释放:及时释放不再使用的资源,如文件句柄、网络连接等

  3. 批量操作:合并多个独立操作,减少系统开销

6.3 错误处理与重试策略

为了提高系统的稳定性和可靠性,系统实现了完善的错误处理与重试策略:

  1. 分级错误处理:根据错误类型和严重程度,采取不同的处理策略

  2. 自适应重试:根据失败次数和类型,动态调整重试间隔和次数

  3. 故障隔离:确保单个设备或应用的故障不会影响整个系统的运行

6.4 性能优化成果

通过一系列的优化措施,系统在以下方面取得了显著的性能提升:

  1. 启动速度提升:系统启动时间减少了约40%

  2. 内存占用降低:内存占用减少了约30%

  3. CPU使用率降低:CPU使用率降低了约25%

  4. 资源消耗降低:经过优化的通信方案和资源管理机制,在低端Windows设备上也能稳定运行

  5. 用户体验改善:直观的状态监控界面,使得操作人员能够实时了解系统运行状态

6.2 技术难点与解决方案

在项目实施过程中,我们遇到了多个技术难点,通过深入分析和创新解决方案,成功克服了这些挑战:

  1. 跨平台通信问题:通过ADB广播与Socket通信相结合的混合通信方案,解决了在不同平台和设备上的通信稳定性问题

  2. OCR识别准确率:通过优化OCR引擎配置和关键词库,提高了广告识别的准确率

  3. 多设备并发控制:通过Python的multiprocessing模块,实现高效的多设备并发控制

  4. 资源占用优化:通过临时文件清理、资源回收和批量操作优化,显著降低了系统的资源占用

  5. 系统稳定性保障:通过全面的错误处理、重试机制和降级策略,提高了系统的稳定性和可靠性

6.3 未来技术展望

基于当前的项目实践,我们对Android广告监测系统的未来发展方向有以下展望:

  1. AI驱动的广告识别:引入深度学习模型,提高广告识别的准确率和泛化能力,减少对关键词匹配的依赖

  2. 实时数据分析:增加实时数据分析模块,对采集到的广告数据进行实时分析和统计

  3. 云原生架构:将系统迁移到云原生架构,提高系统的可扩展性和弹性

  4. 移动端管理应用:开发专用的移动端管理应用,实现对监测系统的远程管理和控制

  5. 多平台支持:扩展系统支持iOS等其他移动操作系统,实现更全面的广告监测能力

07

七、结语

Android广告监测系统的成功实施,充分展示了自动化技术、跨平台通信、OCR识别等多种技术的综合应用价值。通过不断的技术创新和优化,我们成功解决了在低端Windows设备上的通信性能问题,为广告监测领域提供了一套高效、可靠、稳定的自动化解决方案。

在未来的发展中,我们将继续关注技术前沿,不断优化和扩展系统功能,为广告监测行业提供更加先进的技术支持和服务。同时,我们也希望通过本文的分享,为相关领域的技术人员提供一些有益的参考和启示,共同推动移动应用自动化监测技术的发展和进步。



【声明】内容源于网络
0
0
搜狐技术产品
这里是搜狐技术产品的知识分享平台。作为中国领先的互联网品牌,在拥有媒体、视频、搜索、游戏四大业务平台和超7亿用户的背后,搜狐始终致力于技术的创新与实践,更多实战干货和技术资讯将在此与您分享。
内容 1173
粉丝 0
搜狐技术产品 这里是搜狐技术产品的知识分享平台。作为中国领先的互联网品牌,在拥有媒体、视频、搜索、游戏四大业务平台和超7亿用户的背后,搜狐始终致力于技术的创新与实践,更多实战干货和技术资讯将在此与您分享。
总阅读156
粉丝0
内容1.2k