I'm having some problems making PreferenceScreen
and applicationIdSuffix
work together.
Supposing my app package/applicationId
is com.myapp
in Gradle and in AndroidManifest.xml, and applicationIdSuffix
is defined as:
buildTypes {
debug {
applicationIdSuffix '.dev'
}
}
If I define a PreferenceScreen
as the following
<PreferenceScreen
android:key="key_about" android:summary="something" android:title="About">
<intent
android:targetClass="com.myapp.activities.AboutActivity"
android:targetPackage="com.myapp" />
</PreferenceScreen>
when launching the debug version of the app I get an exception
java.lang.SecurityException: Permission Denial: starting Intent { (...) } from ProcessRecord{(...)} (pid=13658, uid=10105) not exported from uid 10067
which makes sense, as I'm trying to launch an activity from a different application. The problem is that I can't find a way to Android launch the right activity.
If I change targetClass
to ".activities.AboutActivity" it still can't find the activity
ActivityNotFoundException: Unable to find explicit activity class {com.myapp.dev/.activities.AboutActivity}
I even tried to define a value for each of the versions with the correct package:
android:targetClass="@string/classname"
android:targetPackage="@string/packagename"
but it can't find the right activity:
ActivityNotFoundException: Unable to find explicit activity class
{com.myapp.dev/com.myapp.dev.activities.AboutActivity};
have you declared this activity in your AndroidManifest.xml?
So how can I make this work?
There is currently no direct way to include the effective
applicationId
into other XML files than the AndroidManifest (where it is available as${applicationId}
), so you need to create a string property for it.Because the gradle
applicationId
value changes based on the flavor, you can not use it directly to define the string property. Instead, you need to create anafterEvaluate
rule inbuild.gradle
to generate it for all variants:This will create a
@string/application_id
(orR.string.application_id
) that you can use wherever needed, e.g. in your layout / preferences XML (the class name doesn't need to be changed because it is based on the java package that's the same for all flavors):This solution is based on https://gist.github.com/Takhion/74b67cb518e90faf2708 which also provides a provider property.
Your confusion comes from the fact that
applicationIdSuffix
only changes the package name of the application (its unique id), but does not change the java package name of your classes inside the application, including your Activity.This means that you should declare in your preferences:
Where
targetClass
is always the same, whiletargetPackage
depends on your build type and can becom.myapp
orcom.myapp.dev
.What I do in my app is attach an
onPreferenceClickListener
to the preference in its host activity, and build the intent inside that listener'sonPreferenceClick
method. By generating the intent from code, you directly reference the target class and the question of packages never comes up.