一個(gè)教訓(xùn)

這是一個(gè)關(guān)于targetSdkVersion的教訓(xùn)。

之前有用戶反饋,在android12設(shè)備上,會報(bào)藍(lán)牙權(quán)限適配導(dǎo)致的crash:

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

看了下,Android 12上將原來的android.permission.BLUETOOTH權(quán)限拆分成了三個(gè):
BLUETOOTH_SCAN、BLUETOOTH_ADVERTISEBLUETOOTH_CONNECT
看了下適配文檔,將SDK的AndroidManifest里的藍(lán)牙權(quán)限做了如下修改:

- <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代碼里做了些相關(guān)改動。正好辦公室也借不到Android12的設(shè)備。目測了下代碼,感覺沒啥問題,就提交了。

幾個(gè)星期后,有客戶反饋,Android 12上藍(lán)牙,報(bào)藍(lán)牙權(quán)限缺失導(dǎo)致的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設(shè)備上運(yùn)行的APP,如果targetSdkVersion小于31并且沒有android.Manifest.permission.BLUETOOTH這個(gè)權(quán)限,運(yùn)行到這里,就會拋出藍(lán)牙權(quán)限缺失異常。
目前這個(gè)階段,大部分客戶的APP應(yīng)該是沒有適配Android12的,那么targetSdkVersion肯定是小于31,然后升級了之前我改動過的SDK,沒有android.permission.BLUETOOTH這個(gè)權(quán)限,導(dǎo)致crash。

這是第一個(gè)教訓(xùn),沒有經(jīng)過驗(yàn)證的代碼就有可能存在bug。

然后客戶又說,老的SDK打包的APK在Android 12上可以運(yùn)行,并且藍(lán)牙相關(guān)功能也正常。
當(dāng)時(shí)就覺得奇怪,既然你運(yùn)行正常,那第一個(gè)客戶是怎么crash的?

但是由于比較匆忙,也沒細(xì)想,直接在相關(guān)代碼里加了這么一個(gè)判斷,規(guī)避了crash。

if (Build.VERSION.SDK_INT < 31 || context.getApplicationInfo().targetSdkVersion < 31) {
      return checkPermission(context, BLUETOOTH); //對老權(quán)限校驗(yàn),不通過則不往下執(zhí)行。
}

于是又犯了第二個(gè)錯(cuò)誤,沒有理清bug的根源就胡亂修改。

后面越想越不對,新Feature不都應(yīng)該是前向兼容的么?新的設(shè)備上運(yùn)行targetSdkVersion還比較老的APP應(yīng)該是沒有問題才對。而且我的第二個(gè)修改會導(dǎo)致targetSdkVersion < 31的APP在android 12上無法運(yùn)行,因?yàn)?code>AndroidManifest里的權(quán)限是新的:

<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" />

我的第二個(gè)修改肯定是不對的。而且Google肯定也不會犯這么低級的錯(cuò)誤。

那么第一個(gè)客戶又是怎么crash的呢?

于是又去詢問第一個(gè)用戶的,問他targetSdkVersion是多少。

果然,他說是31。這下真相大白,targetSdkVersion指向了Android12,但是有沒有做相應(yīng)的代碼適配,crash是必然。這個(gè)適配操作理應(yīng)由客戶端完成,而不是SDK。

于是,將SDK兩次修改的代碼全部回退,至此,問題告一段落。

好在我們的客戶量不大, 不然上線的錯(cuò)誤修改勢必會導(dǎo)致大規(guī)模用戶使用異常,這是災(zāi)難級別的。

以后去大廠了可不能犯這種低級錯(cuò)誤,要理清問題根源在修改代碼,牢記牢記。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容