美文网首页
一个教训

一个教训

作者: 拿拿guardian | 来源:发表于2022-03-24 16:09 被阅读0次

    这是一个关于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里的蓝牙权限做了如下修改:

    - <uses-permission android:name="android.permission.BLUETOOTH" />
    + <uses-permission android:name="android.permission.BLUETOOTH"
    +    android:maxSdkVersion="30" />
    + <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
    

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

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

    java.lang.SecurityException: Need BLUETOOTH permission
    at android.bluetooth.BluetoothHeadset.<init>(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里的权限是新的:

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    

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

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

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

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

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

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

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

    相关文章

      网友评论

          本文标题:一个教训

          本文链接:https://www.haomeiwen.com/subject/wlokjrtx.html