一个教训

这是一个关于targetSdkVersion的教训。

之前有用户反馈,在android12设备上,会报蓝牙权限适配导致的crash:

Caused by: Java.lang.SerurityException: Need android.permission.BlUETOOTH_CONNECT permission for android.content.AttributionSource@70c2370b: getName

看了下,Android 12上将原来的android.permission.BLUETOOTH权限拆分成了三个:
BLUETOOTH_SCANBLUETOOTH_ADVERTISEBLUETOOTH_CONNECT
看了下适配文档,将SDK的AndroidManifest里的蓝牙权限做了如下修改:

- 
+ 
+ 

然后,Java代码里做了些相关改动。正好办公室也借不到Android12的设备。目测了下代码,感觉没啥问题,就提交了。

几个星期后,有客户反馈,Android 12上蓝牙,报蓝牙权限缺失导致的crash:

java.lang.SecurityException: Need BLUETOOTH permission
at android.bluetooth.BluetoothHeadset.(BluetoothHeadset.java:426)
at android.bluetooth.BluetoothAdapter.getProfileProxy(BluetoothAdapter.java:3139)

看了下源码,crash在下面代码:

// Preserve legacy compatibility where apps were depending on
// registerStateChangeCallback() performing a permissions check which
// has been relaxed in modern platform versions
if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R
         && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH)
                  != PackageManager.PERMISSION_GRANTED) {
       throw new SecurityException("Need BLUETOOTH permission");
}

也就是在Android12设备上运行的APP,如果targetSdkVersion小于31并且没有android.Manifest.permission.BLUETOOTH这个权限,运行到这里,就会抛出蓝牙权限缺失异常。
目前这个阶段,大部分客户的APP应该是没有适配Android12的,那么targetSdkVersion肯定是小于31,然后升级了之前我改动过的SDK,没有android.permission.BLUETOOTH这个权限,导致crash。

这是第一个教训,没有经过验证的代码就有可能存在bug。

然后客户又说,老的SDK打包的APK在Android 12上可以运行,并且蓝牙相关功能也正常。
当时就觉得奇怪,既然你运行正常,那第一个客户是怎么crash的?

但是由于比较匆忙,也没细想,直接在相关代码里加了这么一个判断,规避了crash。

if (Build.VERSION.SDK_INT < 31 || context.getApplicationInfo().targetSdkVersion < 31) {
      return checkPermission(context, BLUETOOTH); //对老权限校验,不通过则不往下执行。
}

于是又犯了第二个错误,没有理清bug的根源就胡乱修改。

后面越想越不对,新Feature不都应该是前向兼容的么?新的设备上运行targetSdkVersion还比较老的APP应该是没有问题才对。而且我的第二个修改会导致targetSdkVersion < 31的APP在android 12上无法运行,因为AndroidManifest里的权限是新的:




我的第二个修改肯定是不对的。而且Google肯定也不会犯这么低级的错误。

那么第一个客户又是怎么crash的呢?

于是又去询问第一个用户的,问他targetSdkVersion是多少。

果然,他说是31。这下真相大白,targetSdkVersion指向了Android12,但是有没有做相应的代码适配,crash是必然。这个适配操作理应由客户端完成,而不是SDK。

于是,将SDK两次修改的代码全部回退,至此,问题告一段落。

好在我们的客户量不大, 不然上线的错误修改势必会导致大规模用户使用异常,这是灾难级别的。

以后去大厂了可不能犯这种低级错误,要理清问题根源在修改代码,牢记牢记。

你可能感兴趣的:(一个教训)