从广播接收器启动 activity 意图显示错误 activity
Starting an activity intent from a broadcast receiver shows the wrong activity
我正在制作一个库,可用于将破解和进入检测合并到任何应用程序中
有一个 arduino 设置为房子的闹钟,它会在触发时向特定 phone 发送短信
在我的 sdk 中,我注册了一个短信接收器,它在收到带有特定文本的短信时,应该显示全屏 activity(也在锁屏顶部),这将提醒用户
我创建了一个应用程序来测试此行为
应用程序包是:com.example.demo
图书馆的包是:com.example.sdk
短信接收者看起来像这样:
class SMSReceiver : BroadcastReceiver() {
companion object {
const val TAG = "SMSReceiver"
}
private val logger by lazy { Injections.logger }
override fun onReceive(context: Context?, intent: Intent?) {
logger.log(TAG) { "Got sms" }
val ctx = context ?: return
val bundle = intent?.extras ?: return
val format = bundle.getString("format") ?: return
val pdus = (bundle["pdus"] as? Array<*>) ?: return
for (idx in pdus.indices) {
val pdu = pdus[idx] as? ByteArray ?: continue
val msg = SmsMessage.createFromPdu(pdu, format)
if (msg.messageBody.startsWith("theft event", true)) {
logger.log(TAG) { "Got theft event" }
abortBroadcast()
showTheftActivity(ctx, msg.messageBody)
break
}
}
}
private fun showTheftActivity(context: Context, messageBody: String) {
val intent = Intent(context, TheftActivity::class.java)
intent.addFlags(Intent.FLAG_FROM_BACKGROUND)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// .addCategory(Intent.CATEGORY_LAUNCHER)
val location = messageBody.split(" ").getOrNull(2)
if (location != null) {
val coords = location.split(",")
if (coords.size == 2) {
val x = coords[0].toBigDecimalOrNull()
val y = coords[1].toBigDecimalOrNull()
if (x != null && y != null) {
intent.putExtra(TheftActivity.X, x.toString())
intent.putExtra(TheftActivity.Y, y.toString())
}
}
}
context.startActivity(intent)
}
}
应该显示在所有内容之上的 activity 是这样的:
class TheftActivity : Activity() {
companion object {
const val X = "locationX"
const val Y = "locationY"
}
private val x: String? by lazy { intent.getStringExtra(X) }
private val y: String? by lazy { intent.getStringExtra(Y) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_theft)
val location = findViewById<Button>(R.id.locate)
if (x != null && y != null) {
location.setOnClickListener { Toast.makeText(applicationContext, "Going to $x , $y", Toast.LENGTH_SHORT).show() }
location.isEnabled = true
finish()
} else {
location.isEnabled = false
}
findViewById<Button>(R.id.cancel).setOnClickListener {
finish()
}
turnScreenOnAndKeyguardOff()
}
private fun turnScreenOnAndKeyguardOff() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
}
with(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
requestDismissKeyguard(this@TheftActivity, null)
}
}
}
override fun onDestroy() {
super.onDestroy()
turnScreenOffAndKeyguardOn()
}
private fun turnScreenOffAndKeyguardOn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(false)
setTurnScreenOn(false)
} else {
window.clearFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
}
}
}
SDK 的 android 清单包含以下内容:
<application>
<activity
android:name=".ui.TheftActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:label="@string/title_activity_theft"
android:showOnLockScreen="true"
android:theme="@style/Theme.Sdk.Fullscreen" />
<receiver
android:name=".receivers.SMSReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
在模拟器上测试时,我发送短信触发盗窃事件
如果用于测试的 activity(com.example.demo 包中的那个)没有关闭,那么它会被带到前面,但是如果它被关闭,则什么也不会发生(尽管我确实看到了来自接收者的日志消息)
如何让我的短信接收器打开 TheftActivity 而不是主程序包中的主 activity?
编辑:如果有帮助,盗窃 activity 似乎开始然后立即被摧毁
由于 Android Q
中实施的限制,系统似乎无法将 activity 带到前台
使用 Android Q,如果您的应用不包含下面 link 中列出的例外情况,则无法从后台自动启动 activity。
https://developer.android.com/guide/components/activities/background-starts
可能的解决方案:
我正在制作一个库,可用于将破解和进入检测合并到任何应用程序中
有一个 arduino 设置为房子的闹钟,它会在触发时向特定 phone 发送短信
在我的 sdk 中,我注册了一个短信接收器,它在收到带有特定文本的短信时,应该显示全屏 activity(也在锁屏顶部),这将提醒用户
我创建了一个应用程序来测试此行为
应用程序包是:com.example.demo
图书馆的包是:com.example.sdk
短信接收者看起来像这样:
class SMSReceiver : BroadcastReceiver() {
companion object {
const val TAG = "SMSReceiver"
}
private val logger by lazy { Injections.logger }
override fun onReceive(context: Context?, intent: Intent?) {
logger.log(TAG) { "Got sms" }
val ctx = context ?: return
val bundle = intent?.extras ?: return
val format = bundle.getString("format") ?: return
val pdus = (bundle["pdus"] as? Array<*>) ?: return
for (idx in pdus.indices) {
val pdu = pdus[idx] as? ByteArray ?: continue
val msg = SmsMessage.createFromPdu(pdu, format)
if (msg.messageBody.startsWith("theft event", true)) {
logger.log(TAG) { "Got theft event" }
abortBroadcast()
showTheftActivity(ctx, msg.messageBody)
break
}
}
}
private fun showTheftActivity(context: Context, messageBody: String) {
val intent = Intent(context, TheftActivity::class.java)
intent.addFlags(Intent.FLAG_FROM_BACKGROUND)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// .addCategory(Intent.CATEGORY_LAUNCHER)
val location = messageBody.split(" ").getOrNull(2)
if (location != null) {
val coords = location.split(",")
if (coords.size == 2) {
val x = coords[0].toBigDecimalOrNull()
val y = coords[1].toBigDecimalOrNull()
if (x != null && y != null) {
intent.putExtra(TheftActivity.X, x.toString())
intent.putExtra(TheftActivity.Y, y.toString())
}
}
}
context.startActivity(intent)
}
}
应该显示在所有内容之上的 activity 是这样的:
class TheftActivity : Activity() {
companion object {
const val X = "locationX"
const val Y = "locationY"
}
private val x: String? by lazy { intent.getStringExtra(X) }
private val y: String? by lazy { intent.getStringExtra(Y) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_theft)
val location = findViewById<Button>(R.id.locate)
if (x != null && y != null) {
location.setOnClickListener { Toast.makeText(applicationContext, "Going to $x , $y", Toast.LENGTH_SHORT).show() }
location.isEnabled = true
finish()
} else {
location.isEnabled = false
}
findViewById<Button>(R.id.cancel).setOnClickListener {
finish()
}
turnScreenOnAndKeyguardOff()
}
private fun turnScreenOnAndKeyguardOff() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
}
with(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
requestDismissKeyguard(this@TheftActivity, null)
}
}
}
override fun onDestroy() {
super.onDestroy()
turnScreenOffAndKeyguardOn()
}
private fun turnScreenOffAndKeyguardOn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(false)
setTurnScreenOn(false)
} else {
window.clearFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
}
}
}
SDK 的 android 清单包含以下内容:
<application>
<activity
android:name=".ui.TheftActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:label="@string/title_activity_theft"
android:showOnLockScreen="true"
android:theme="@style/Theme.Sdk.Fullscreen" />
<receiver
android:name=".receivers.SMSReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
在模拟器上测试时,我发送短信触发盗窃事件
如果用于测试的 activity(com.example.demo 包中的那个)没有关闭,那么它会被带到前面,但是如果它被关闭,则什么也不会发生(尽管我确实看到了来自接收者的日志消息)
如何让我的短信接收器打开 TheftActivity 而不是主程序包中的主 activity?
编辑:如果有帮助,盗窃 activity 似乎开始然后立即被摧毁
由于 Android Q
中实施的限制,系统似乎无法将 activity 带到前台使用 Android Q,如果您的应用不包含下面 link 中列出的例外情况,则无法从后台自动启动 activity。
https://developer.android.com/guide/components/activities/background-starts
可能的解决方案: