android:exported:在 Android 12 上使用 Kotlin 避免崩溃

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么您的应用在 Android 12 上突然无法启动?

\n\n

您将 targetSdkVersion 更新到 31 或更高版本,构建了 APK,启动时——却遇到了崩溃,并显示一条神秘消息:

\n\n
android:exported needs to be explicitly specified for <activity>. \nApps targeting Android 12 and higher are required to specify \nan explicit value for `android:exported` when the corresponding \ncomponent has an intent filter defined.
\n\n

熟悉吗?如果您浏览过 Stack Overflow,您会发现这个问题已经积累了数千次浏览。开发者们惊慌失措,用户们则困惑不解。但不要急着删除项目。在本文中,我们将弄清楚 android:exported 到底是什么,为什么 Google 收紧了要求,以及如何用 Kotlin 快速修复这个错误。我们开始吧!

\n\n

什么是 android:exported,它有什么用?

\n\n

android:exported 是 AndroidManifest.xml 中的一个属性,它控制其他应用(或系统本身)是否可以启动您的组件(Activity、Service、BroadcastReceiver 或 ContentProvider)。如果该属性设置为 true——则该组件可从外部访问。如果设置为 false——则只能在您的应用内部访问。

\n\n

在 Android 12(API 31)之前,此属性是可选的。如果您没有指定它,系统会自行决定该组件是否可访问:

\n
    \n
  • 如果 Activity 有 <intent-filter>——系统会认为 exported = true。
  • \n
  • 如果没有过滤器——则 exported = false。
  • \n
\n\n

但这种“自动”行为是一个安全漏洞。想象一下:您编写了一个用于登录应用的 Activity,却不小心添加了 intent-filter。任何第三方应用都可以调用您的 Activity 并窃取令牌。因此 Google 决定:从 Android 12 开始,对于任何带有 <intent-filter> 的组件,您必须显式指定 android:exported。

\n\n

错误在实践中是什么样子的?

\n\n

假设您有一个简单的清单文件:

\n\n
<activity android:name=".MainActivity">\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n</activity>
\n\n

如果 targetSdkVersion = 31 或更高,您在编译或启动时会遇到错误。解决方案是添加 android:exported:

\n\n
<activity \n    android:name=".MainActivity"\n    android:exported="true">\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n</activity>
\n\n

对于从桌面启动的主 Activity,exported 必须为 true——否则启动器将无法打开它。

\n\n

如何正确修复:分步指南

\n\n

步骤 1. 打开 AndroidManifest.xml

\n

找到所有带有 <intent-filter> 的 <activity>、<service>、<receiver> 和 <provider>。为每一个添加 android:exported。

\n\n

步骤 2. 确定属性值

\n

这是一个简单的规则:

\n
    \n
  • true——如果组件应该可以从其他应用访问(例如,用于通过 Google 登录的 Activity、用于系统事件的 BroadcastReceiver、带有 LAUNCHER 过滤器的主 Activity)。
  • \n
  • false——如果组件仅在您的应用内部使用(例如,通过您自己代码中的按钮点击打开的 Activity)。
  • \n
\n\n

步骤 3. 不同场景的示例

\n\n

场景 1:主 Activity(启动器)

\n
                

博客

书籍推荐