【问题标题】:Using PreferenceScreen with applicationIdSuffix将 PreferenceScreen 与 applicationIdSuffix 一起使用
【发布时间】:2019-03-22 21:11:01
【问题描述】:

我在使 PreferenceScreenapplicationIdSuffix 一起工作时遇到了一些问题。

假设我的应用包/applicationId在Gradle和AndroidManifest.xml中为com.myappapplicationIdSuffix定义为:

buildTypes {
    debug {
        applicationIdSuffix '.dev'
    }
}

如果我将PreferenceScreen 定义如下

<PreferenceScreen
    android:key="key_about" android:summary="something" android:title="About">
    <intent
        android:targetClass="com.myapp.activities.AboutActivity"
        android:targetPackage="com.myapp" />
</PreferenceScreen>

在启动应用程序的调试版本时出现异常

java.lang.SecurityException: Permission Denial: starting Intent { (...) } from ProcessRecord{(...)} (pid=13658, uid=10105) not exported from uid 10067

这是有道理的,因为我正试图从不同的应用程序启动一个活动。问题是我找不到让 Android 启动正确 Activity 的方法。

如果我将targetClass 更改为“.activities.AboutActivity”,它仍然找不到活动

ActivityNotFoundException: Unable to find explicit activity class {com.myapp.dev/.activities.AboutActivity}

我什至尝试使用正确的包为每个版本定义一个值:

android:targetClass="@string/classname"
android:targetPackage="@string/packagename"

但它找不到正确的活动:

ActivityNotFoundException: Unable to find explicit activity class
    {com.myapp.dev/com.myapp.dev.activities.AboutActivity};
have you declared this activity in your AndroidManifest.xml?

那么我怎样才能做到这一点呢?

【问题讨论】:

  • 根据这里的异常,我认为它说你应该在清单中定义你的 AboutActivity。

标签: android gradle android-manifest preferenceactivity


【解决方案1】:

您的困惑来自applicationIdSuffix 仅更改应用程序的包名称(其唯一ID),但不会更改应用程序内部类的Java 包名称,包括您的Activity。

这意味着你应该在你的偏好中声明:

android:targetClass="com.myapp.activities.AboutActivity"
android:targetPackage="@string/packagename"

其中targetClass 始终相同,而targetPackage 取决于您的构建类型,可以是com.myappcom.myapp.dev

【讨论】:

  • 如果 applicationId 没有后缀,这不会仍然失败吗?
  • 您应该在与声明的构建类型匹配的 2 个不同文件夹中定义字符串常量,并为字符串赋予与应用程序 ID 相同的值(带和不带后缀)。不幸的是,还不能在资源中使用 applicationId 作为变量,您只能在清单中使用。
【解决方案2】:

目前没有直接的方法可以将有效的applicationId 包含到除 AndroidManifest 之外的其他 XML 文件中(其中它以 ${applicationId} 的形式提供),因此您需要为其创建一个字符串属性。

因为gradleapplicationId的值会根据flavor改变,所以不能直接用它来定义string属性。相反,您需要在build.gradle 中创建一个afterEvaluate 规则来为所有变体生成它:

afterEvaluate {
    android.applicationVariants.all { variant ->
        variant.resValue 'string', 'application_id', variant.applicationId
    }
}

这将创建一个@string/application_id(或R.string.application_id),您可以在需要时使用它,例如在您的布局/首选项 XML 中(不需要更改类名,因为它基于所有风格都相同的 java 包):

<PreferenceScreen
    android:key="key_about" android:summary="something" android:title="About">
    <intent
        android:targetClass="com.myapp.activities.AboutActivity"
        android:targetPackage="@string/application_id" />
</PreferenceScreen>

此解决方案基于https://gist.github.com/Takhion/74b67cb518e90faf2708,它还提供了提供者属性。

【讨论】:

  • 谢谢! afterEvaluate 应该在productFlavors 之下(本身在android 之下)
【解决方案3】:

我在我的应用程序中所做的是将onPreferenceClickListener 附加到其主机活动中的首选项,并在该侦听器的onPreferenceClick 方法中构建意图。通过从代码生成意图,您可以直接引用目标类,并且永远不会出现包的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多