解决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模式:
-
MTP (媒体传输协议)
-
PTP (图片传输协议)
-
充电模式
-
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