解决USB图库应用开发中的两大棘手问题

0 阅读3分钟

解决USB图库应用开发中的两大棘手问题

最近我负责开发了一款名为"USB图库"的车载应用。这款应用的核心功能是在检测到U盘插入后,自动读取并展示U盘中的图片,同时支持将喜欢的图片设置为车载系统的壁纸。在开发过程中,我遇到了两个奇葩的问题,现在,将这两个问题记录下来。


问题一:为什么插入U盘后需要关闭 ADB 才能正常扫描?

  • 现象描述

当U盘插入车载系统后,应用无法检测到U盘中的图片。只有在关闭ADB调试模式后,U盘才能被正常识别和扫描。整个测试过程中,发现U盘的插入拔出接收不到任何广播。

public class UsbReceiver extends BroadcastReceiver {
    public static final String TAG = "USBReceiver";
    private final static String MEDIA_MOUNTED = Intent.ACTION_MEDIA_MOUNTED;
    private final static String MEDIA_UNMOUNTED = Intent.ACTION_MEDIA_UNMOUNTED;
    private final static String MEDIA_EJECT = Intent.ACTION_MEDIA_EJECT;
    private final static String SCANNER_STARTED = Intent.ACTION_MEDIA_SCANNER_STARTED;
    private final static String SCANNER_FINISHED = Intent.ACTION_MEDIA_SCANNER_FINISHED;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "onReceive: action = " + action);
        assert action != null;
        Uri data = intent.getData();
        String mountedPath = "";
        if (data != null) {
            mountedPath = intent.getData().toString();
        }
        switch (action) {
            // sd卡被插入,且已经挂载
case MEDIA_MOUNTED:
                break;
            case MEDIA_EJECT: 
                break;
            // sd卡存在,但还没有挂载
case MEDIA_UNMOUNTED:
                break;
            case SCANNER_STARTED: 
                break;
            case SCANNER_FINISHED:
                break;
            default:
                break;
        }
    }
}
  • 问题分析

Android设备支持多种USB模式:

  1. MTP (媒体传输协议)

  2. PTP (图片传输协议)

  3. 充电模式

  4. ADB调试模式

在Android系统中,ADB调试和USB存储设备共享同一个USB接口。当ADB处于活动状态时,系统会优先将USB接口分配给调试功能,导致U盘无法获得正常的挂载权限。

  • 解决方案

为了测试功能,插入U盘验证图片扫描,需要将adb的调试模式关闭。关闭后就能正常扫描出图片。


问题二:APK推送后系统启动失败 - 签名验证问题

  • 现象描述

在该APP中,有一个功能设置壁纸,当点击设置壁纸时, 会将当前的这一张图片,拷贝到: **/data/user_de/package/files**目录,遇到了一个奇怪的问题,图片已经拷贝到了这个目录,但是launcher项目访问不到这张壁纸图片。

  • 问题分析

需要跨应用访问私有目录需要Liunx分配相同UID, 因此开发的USB图库app需要声明

android:sharedUserId="android.uid.system"

当声明为系统应用时,系统的安装器有严格的签名验证,这就导致了推包到车机系统后,重新上电车机系统一直启动不起来。原因就是apk没有使用系统的签名文件签名。

  • 解决方案

安装的apk必须使用系统的签名文件签名。

获取系统的签名文件

# 1. platform.pk8 - 私钥文件
# 2. platform.x509.pem - 证书文件
# 3. signapk.jar - 签名工具

给apk签名:

# 使用系统签名对APK进行签名
java -jar signapk.jar platform.x509.pem platform.pk8 input.apk output.apk

# 验证签名信息
keytool -printcert -jarfile output.apk