[英]Gson.toJson for java.io.File giving "{}" after migrating to API 31 Android 12
[英]telephonyManager.listen not working after targetSdkVersion is set to 31 or android 12
在我將 targetSdkVersion 升級到 31 之后,telephonyManager.listen 無法正常工作。 考慮以下代碼行:
telephonyManager.listen(phoneStateListener,PhoneStateListener.LISTEN_CALL_STATE);
logcat 錯誤消息如下所示:
2022-02-27 13:51:36.313 6426-6426/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.app, PID: 6426
java.lang.RuntimeException: Unable to start service com.example.app.myPlayService@7ace64e with Intent { cmp=com.example.app/.myPlayService (has extras) }: java.lang.SecurityException: listen
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4657)
at android.app.ActivityThread.access$2000(ActivityThread.java:247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2091)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.SecurityException: listen
at android.os.Parcel.createExceptionOrNull(Parcel.java:2425)
at android.os.Parcel.createException(Parcel.java:2409)
at android.os.Parcel.readException(Parcel.java:2392)
at android.os.Parcel.readException(Parcel.java:2334)
at com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy.listenWithEventList(ITelephonyRegistry.java:1036)
at android.telephony.TelephonyRegistryManager.listenFromListener(TelephonyRegistryManager.java:250)
at android.telephony.TelephonyManager.listen(TelephonyManager.java:5999)
at com.example.app.myPlayService.onStartCommand(myPlayService.java:186)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4639)
at android.app.ActivityThread.access$2000(ActivityThread.java:247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2091)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.internal.telephony.TelephonyPermissions.enforceCarrierPrivilege(TelephonyPermissions.java:634)
at com.android.internal.telephony.TelephonyPermissions.checkReadPhoneState(TelephonyPermissions.java:149)
at com.android.internal.telephony.TelephonyPermissions.checkCallingOrSelfReadPhoneState(TelephonyPermissions.java:94)
at com.android.server.TelephonyRegistry.checkListenerPermission(TelephonyRegistry.java:3093)
at com.android.server.TelephonyRegistry.listen(TelephonyRegistry.java:1024)
我在 Android 清單文件上添加了以下權限,但仍然無法正常工作。
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
在定位低於 31 或 Android 12 之前,它運行良好。 Android SDK 31 如何解決這個問題? 提前致謝。
當目標 API 31 TelephonyManager.listen給出: java.lang.SecurityException: listen
TelephonyManager.registerTelephonyCallback也是如此,除非禁用ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION 。
開發人員選項/應用程序兼容性更改/選擇應用程序/為 targetSdkVersion >= 31 啟用
由於 API 級別 31 中不推薦使用TelephonyManager.listen並且 API 級別 31 中添加了TelephonyManager.registerTelephonyCallback ,因此您應該編寫如下代碼:
更新為callStateListener
和phoneStateListener
添加了示例
private void registerCallStateListener() {
if (!callStateListenerRegistered) {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
telephonyManager.registerTelephonyCallback(getMainExecutor(), callStateListener);
callStateListenerRegistered = true;
}
} else {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
callStateListenerRegistered = true;
}
}
}
@RequiresApi(api = Build.VERSION_CODES.S)
private static abstract class CallStateListener extends TelephonyCallback implements TelephonyCallback.CallStateListener {
@Override
abstract public void onCallStateChanged(int state);
}
private boolean callStateListenerRegistered = false;
private CallStateListener callStateListener = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ?
new CallStateListener() {
@Override
public void onCallStateChanged(int state) {
// Handle call state change
}
}
: null;
private PhoneStateListener phoneStateListener = (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) ?
new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String phoneNumber) {
// Handle call state change
}
}
: null;
文檔鏈接:
因為TelephonyCallback.CallStateListener需要Manifest.permission.READ_PHONE_STATE並且此權限具有危險的保護級別,您應該按照本指南請求運行時權限: 請求應用權限
這就是我這樣做的方式:
private suspend fun updateServiceState() {
withContext(Dispatchers.Main) {
telephonyManager.listen(object : PhoneStateListener() {
override fun onServiceStateChanged(state: ServiceState) {
telephonyManager.listen(this, LISTEN_NONE)
...
}
}, PhoneStateListener.LISTEN_SERVICE_STATE)
}
}
我的目標是 Android 12、API 31,但我沒有 READ_PHONE_STATE 權限
您需要在清單中添加權限,正如您所做的那樣,還需要通過調用ActivityCompat.requestPermissions()
動態請求它
相當詳盡的文檔: https ://developer.android.com/training/permissions/requesting
您在提供 LISTEN_CALL_STATE 時進行監聽的調用將觸發 onCallStateChanged() 回調。
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
正如您在文檔中看到的,如果您以 Android 31 或更高版本為目標,則 onCallStateChanged() 需要 READ_PHONE_STATE。
需要權限:針對 API 級別 31+ 的應用程序的 READ_PHONE_STATE。
因此,要解決這個問題,只需在調用監聽調用之前請求權限(但僅當代碼在 Android 31+ 上執行時)如下:
// for API 31+: you need to first check for READ_PHONE_STATE permission to be able to listen to LISTEN_CALL_STATE
if (Build.VERSION.SDK_INT >= 31)
{
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
else // no permission needed
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
如果有人在這里尋找支持 API <= 30 和 API 31+(因為它們必須以不同方式處理)的此代碼的 Kotlin + Flow 版本,這里是 go。
這假定權限由調用 UI 代碼處理。
val callState = callbackFlow {
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
// The thread Executor used to run the listener. This governs how threads are created and
// reused. Here we use a single thread.
val exec = Executors.newSingleThreadExecutor()
if (Build.VERSION.SDK_INT >= 31) {
// SDK >= 31 uses TelephonyManager.registerTelephonyCallback()
val callback = object : TelephonyCallback(), TelephonyCallback.CallStateListener {
override fun onCallStateChanged(state: Int) {
trySend(Pair(state, null))
}
}
telephonyManager.registerTelephonyCallback(exec, callback)
awaitClose {
telephonyManager.unregisterTelephonyCallback(callback)
exec.shutdown()
}
}
else {
// SDK 30 uses TelephonyManager.listen()
@Suppress("OVERRIDE_DEPRECATION")
val callback = object : PhoneStateListener(exec) {
override fun onCallStateChanged(state: Int, phoneNumber: String) {
trySend(Pair(state, phoneNumber))
}
}
telephonyManager.listen(callback, PhoneStateListener.LISTEN_CALL_STATE)
awaitClose {
telephonyManager.listen(callback, 0)
exec.shutdown()
}
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
該流程提供了一個Pair<Int, String?>
,其中 .first 是呼叫.first
, .second
是 API <= 30 中的電話號碼。
我在我的博客上有一個使用 Kotlin + Compose + Flows 的完整示例: https://tdcolvin.medium.com.network-type-in-android-watching-for-5g-4g-3g-2g-capability -a52db23bf3bf
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.