Android11对跨进程显式intent启动activity的限制
背景
今天项目中有用到跨进程启动Activity的知识,通过manifest发现,一个由其他进程调用的Activity配置了android.intent.action.MAIN这个action。所以自己想做个试验,这个action对跨进程启动有没有影响。
代码很简单,就是建了两个工程,第一个工程的textview添加响应事件跳转到第二个。
工程一:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun click(v: View) {
val intent = Intent()
val packageName = "com.example.secondapp"
val className = "com.example.secondapp.SecondActivity"
intent.component = ComponentName(packageName, className)
startActivity(intent)
}
}
xml就不列出来了,就是一个textview加一个点击事件。
工程二:
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
工程二的manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.secondapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="second.app"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
这里不讨论显式,隐式Intent调用的问题,这里直接说我遇到的现象。
本来是一个很正常的调用,之前也都用过,而且翻了几篇文章,也都是这么写并没有错。
但是,在跳转的时候,居然出现了错误。
Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.secondapp/com.example.secondapp.SecondActivity}; have you declared this activity in your AndroidManifest.xml?
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2065)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1727)
at android.app.Activity.startActivityForResult(Activity.java:5315)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
at android.app.Activity.startActivityForResult(Activity.java:5273)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
at android.app.Activity.startActivity(Activity.java:5659)
at android.app.Activity.startActivity(Activity.java:5612)
at com.example.firstapp.MainActivity.click(MainActivity.kt:21)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
at android.view.View.performClick(View.java:7448)
at android.view.View.performClickInternal(View.java:7425)
at android.view.View.access$3600(View.java:810)
at android.view.View$PerformClick.run(View.java:28296)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
开玩笑!怎么可能没有注册manifest,activity是建app自动生成的好吗?
试了一下隐式的通过action启动,没问题。这就有点懵了啊!
带着错误,翻遍了国内国外所有的网站,没有找到自己想要的答案,最后无奈之下决定还是跟着走下android源码,看看到底是到哪里抛出了这个异常。
因为我的模拟器是最新版的android11,但是我的代码是android9的,在debug运行的时候代码行数对不上,无法跟踪。所以,我觉得模拟器降低版本,降低到于代码一样的android9。
经过一番下载,安装,装好了一个android9。0的模拟器
就在我把两个工程装好,准备调试一下的时候,发现点击工程一的textview居然跳转到了第二个工程的activity!!!
没想到浪费了一天时间的问题居然是因为系统问题,不知道android10 还是 android11 对这种通过包名和类名的调用给禁掉了?查阅官方文档也没找到相应的说明,或者哪里有我也没找到。。。
好吧,至于是10 还是 11,等有机会再试吧。
华丽的分割线
觉得还是要去官方文档找一找,看看有没有遗漏的地方,结果果然发现,原来android11对软件包的可见性,有新的规定了!
具体参照这里
Android 11 中的软件包可见性.
文章中说因为最小权限原则,所以这里不是所有的软件包都能在你的应用直接调用了,如果想调用的话,需要在manifest里配置queries标签,然后在里边放上package元素,写上你想要访问的应用的包名,这样才可以显式的跨进程调起Activity。
修改后的第一个工程的xml如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.firstapp">
<queries>
<package android:name="com.example.secondapp"/>
</queries>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这里添加了
<queries>
<package android:name="com.example.secondapp"/>
</queries>
这个标签,表示我想要访问第二个工程的包名。
这样,就可以像之前一样通过包名和类名显式的调用我们第二个工程的Activity了,当然,这里隐式的调用是不受影响的。
除了通过包名访问需要配置,有一些情况的action和data等也需要配置,这里官方文档已经说的很清楚了,就不再举例一一说明了,大家自行查阅就好