Android开发,用Kotlin语言。所有Activity都继承以下BaseActivityClass: package com.example.activitytest
import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import android.app.AlertDialog import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter
open class BaseActivityClass : AppCompatActivity() {
lateinit var receiver: ForceLogoutReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//打印当前实例类名
Log.d("BaseActivity", javaClass.simpleName)
ActivityCollector.addActivity(this)
}
override fun onResume() {
super.onResume()
val intentFilter = IntentFilter()
intentFilter.addAction("com.example.activitytest.FORCE_LOGOUT")
receiver = ForceLogoutReceiver()
registerReceiver(receiver, intentFilter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(receiver)
}
override fun onDestroy() {
super.onDestroy()
ActivityCollector.removeActivity(this)
}
inner class ForceLogoutReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
AlertDialog.Builder(context).apply {
setTitle("Warning")
setMessage("You are forced to be logout. Please try to login again.")
setCancelable(false) //不可取消
setPositiveButton("确定") { _, _ ->
ActivityCollector.finishAll() // 销毁所有Activity
val i = Intent(context, LoginActivity::class.java)
context.startActivity(i) // 重新启动LoginActivity
}
show()
}
}
}
}
编译时有告警如下:
receiver
is missing RECEIVER_EXPORTED
or RECEIVER_NOT_EXPORTED
flag for unprotected broadcasts registered for com.example.activitytest.FORCE_LOGOUT;
Property 'receiver' could be private
请分析原因,并解决,确保没有警告信息。
在Android 12(API 31)及更高版本中,广播接收器需要明确指定其导出状态,以确保应用的安全性。你需要在注册广播接收器时指定RECEIVER_EXPORTED
或RECEIVER_NOT_EXPORTED
标志,以表明广播接收器是否可以接收来自其他应用的广播。
此外,Kotlin编译器警告你receiver
属性可以是私有的,因为它只在BaseActivityClass
内部使用。
以下是修改后的代码,解决了上述警告:
package com.example.activitytest
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import android.app.AlertDialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
open class BaseActivityClass : AppCompatActivity() {
private lateinit var receiver: ForceLogoutReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//打印当前实例类名
Log.d("BaseActivity", javaClass.simpleName)
ActivityCollector.addActivity(this)
}
override fun onResume() {
super.onResume()
val intentFilter = IntentFilter()
intentFilter.addAction("com.example.activitytest.FORCE_LOGOUT")
receiver = ForceLogoutReceiver()
registerReceiver(receiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
}
override fun onPause() {
super.onPause()
unregisterReceiver(receiver)
}
override fun onDestroy() {
super.onDestroy()
ActivityCollector.removeActivity(this)
}
inner class ForceLogoutReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
AlertDialog.Builder(context).apply {
setTitle("Warning")
setMessage("You are forced to be logout. Please try to login again.")
setCancelable(false) //不可取消
setPositiveButton("确定") { _, _ ->
ActivityCollector.finishAll() // 销毁所有Activity
val i = Intent(context, LoginActivity::class.java)
context.startActivity(i) // 重新启动LoginActivity
}
show()
}
}
}
}
将receiver
属性设为私有:
private lateinit var receiver: ForceLogoutReceiver
在注册广播接收器时指定RECEIVER_NOT_EXPORTED
标志:
registerReceiver(receiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
这样修改后,编译时的警告信息应该会消失。RECEIVER_NOT_EXPORTED
标志确保了广播接收器不会接收来自其他应用的广播,从而提高了应用的安全性。