明确Android的intent(-filters)
Android 12 即将发生一项重要变化,它提高了应用程序和平台的安全性。此更改会影响所有 以 Android 12 为目标平台的应用。
具有声明的intent-filters的Activities, services, and broadcast receivers,现在必须明确地声明它们是否应该被导出。
❗️如果您的应用因这些错误消息而失败,则很可能与此更改有关。
Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
List of apks:
[0] ‘…/build/outputs/apk/debug/app-debug.apk’
Installation failed due to: ‘null’
或者
INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI: /data/app/vmdl538800143.tmp/base.apk (at Binary XML file line #…): com.example.package.ActivityName: Targeting S+ (version 10000 and above) requires that an explicit value for android:exported be defined when intent filters are present”
修复
这些错误的解决方法是在任何<activity>
、<activity-alias>
、<service>
或<receiver>
组件中添加android:exported
的属性,这些组件在应用程序AndroidManifest.xml
文件中声明了<intent-filter>
。
⚠️ 不要只是将android:exported=”true”
添加到所有这些组件中!检查每个包含<intent-filter>
定义的组件,并问自己:“我是否希望安装在某人设备上的任何应用程序都能够启动该组件?”。
这个问题的答案取决于应用程序的作用、其他应用程序如何与之互动,以及其他应用程序的具体考虑。以下是一些常见的意图过滤器的例子,并附有建议值和对为什么选择它的解释。
与<category android:name=”android.intent.category.LAUNCHER” />
的Activity。android:exported=”true”
这可能是你的应用程序的MainActivity
,由于安卓上的启动器可能是一个普通的应用程序,这个活动必须被导出,否则启动器将无法启动它。
与<action android:name=”android.intent.action.VIEW” />
的Activity。android:exported=”true”
该活动负责处理来自其他应用程序的 "与其他应用程序一起打开 "动作。
用<action android:name=”android.intent.action.SEND” />
或<action android:name=”android.intent.action.SEND_MULTIPLE”/>
的Activity。android:exported=”true”
这个活动负责处理其他应用程序与它共享的内容。参见从其他应用程序接收简单数据。
用<action android:name=”android.media.browse.MediaBrowserService” />
的Service。android:exported=”true”
如果这是一个将应用程序的媒体库暴露给其他应用程序的Service,那么它应该被导出,以允许其他应用程序连接并浏览该库。该服务可能直接或间接地扩展了 MediaBrowserServiceCompat
。如果不是这样,那么可能就没有必要导出它。
用<action android:name=”com.google.firebase.MESSAGING_EVENT” />
的Service。android:exported=”false”
这是Firebase云信息服务将调用的服务,应该扩展FirebaseMessagingService
。这个服务应该不被导出,因为无论它是否被导出,Firebase都能启动这个组件。更多信息,请参见在Android上设置一个Firebase云消息客户端应用。
接收器Receiver上有<action android:name=”android.intent.action.BOOT_COMPLETED” />
。android:exported=”false”
因为系统正在向广播接收器传递这个动作,所以无论它是否被导出,它都可以这样做。
背景介绍
在Android 12之前,声明了intent-filter的组件(仅限activites, services, and broadcast receivers )会自动导出。
该activity默认为导出。
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"
</intent-filter>
</activity>
这项activity未被导出。
<activity android:name=".MainActivity" />
虽然这似乎是一个合理的默认值,但这里的错误可能会使应用程序受到攻击。例如,假设我们的应用程序有一个播放视频的活动。
<activity android:name=”.PlayVideoActivity” />
后来我们发现,我们从很多地方明确地链接到这个活动,因此,为了让我们的应用程序更加松散地耦合,我们改变了我们的活动,使其包括一个intent-filter,以允许系统选择该活动。
<activity android:name=”.PlayVideoActivity”>
<intent-filter>
<action android:name=”android.intent.action.VIEW” />
<data
android:mimeType=”video/*”
android:scheme=”content” />
</intent-filter>
</activity>
突然间,我们遇到了一个问题。我们的活动只被设计为由我们的应用程序内部使用,但现在却被导出了!这就是为什么我们的活动会被导出。
一旦我们以Android 12为目标,系统将通过要求我们明确android:exported的值来防止这种情况。在这种情况下,我们不希望它被导出,所以我们可以设置该属性,并保持我们的应用程序安全。
<activity
android:name=”.PlayVideoActivity”
android:exported=”false”>
<intent-filter>
<action android:name=”android.intent.action.VIEW” />
<data
android:mimeType=”video/*”
android:scheme=”content” />
</intent-filter>
</activity>
TLDR
为了提高安全性,安卓12将有一个重要的变化。以该版本为目标的应用程序将需要明确声明任何activity
、activity-alias
、service
或广播receiver
的android:exported
属性的值,这些文件在其AndroidManifest.xml
文件中包括一个intent-filter。如果不这样做,该应用程序将不能被安装。
仔细考虑将这个属性设置为什么值,当有疑问时,倾向于设置android:exported=”false”
。
有关intent和intent-filters的更多信息,请参见接收隐含的intent。
有关安全和隐私的其他更新的更多信息,请参见本页面。
有关Android 12中的所有变化的更多信息,请查看开发预览版1的博文!。
我有同样的问题!此外,它是否影响我在模拟器或真实设备上运行应用程序?我试着在外部libs的缓存清单中添加exported来检查,但仍然得到错误。
你简直是救了我的命。我有这个错误已经好几个星期了!
是的,这很有效。如果你一直收到和我一样的信息,你必须检查你正在使用的库。我不得不删除一个库,现在一切都正常了。
对于BOOT_COMPLETE接收器,即使导出是false的,系统应用程序也能进行通信吗?
为什么会被添加?
那我怎么知道该放什么呢,除了试一试,看一看是否能正常工作?
例如,androidx.core.content.FileProvider案例是否应该被导出,或者不导出?
为什么谷歌不能为我们提供正确迁移的工具?这是一个如此重要的变化,可能会引起问题。
你可以将接收器设置为exported="false",因为 "系统正在交付这个动作",这个解释似乎不对,因为在使用 "android.intent.action.MY_PACKAGE_REPLACED "时,我看到它需要被设置为 "true"。不过不确定 "android.appwidget.action.APPWIDGET_UPDATE "的情况(似乎在设置为false时可以工作)。
这一点和包装的可见性。
我仍然不明白在许多情况下如何正确设置。这种烦人的事情...为什么还需要这些改变呢?
😅
我正试图将我们的应用程序升级到目标Android 12,但我们的一些依赖项没有在其清单中明确定义导出属性(如Stripe),所以当清单被合并时,结果是一个无效的清单,所以应用程序无法安装。在这种情况下,我们应该怎么做?