Creating activity-alias for build variants using gradle - android

I recently merged 4 similar but independent apps into one gradle project and setup gradle to use build variants for deploying each one independently. Because I've merged these projects that were previously independed, I needed to rename some packages, including the package for the launcher activity. In order to preserve the launcher links for my current user base, I wanted to use an activity-alias to point the old launcher links to the new launcher activity. So far so good.
However, since I have multiple build variants, I need several different aliases to link back to the new launch activity. I looked into gradle's new manifest merging solution and looked into using placeholders for the alias name, however, when I drop the placeholder under the alias, it refuses to acknowledge the right package. The app will crash with
Starting: Intent { act=android.intent.action.MAIN
cat=[android.intent.category.LAUNCHER]
cmp=com.stuart.android.flavor1/${packageName}.NewLauncherActivity }
Error type 3
Error: Activity class {com.stuart.android.flavor1/${packageName}.NewLauncherActivity} does not exist.
Below is the activity-alias from my manifest and the gradle build file. I need to find a way to insert the package name for each build variant into the alias for each build I do. com.stuart.android.main is the common package among all flavors and is the location of the new launch activity. I'm using Android Studio 0.6.1 with the 0.11 Gradle plugin. Any help is appreciated!
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stuart.android.main"
android:installLocation="auto">
<application android:icon="#drawable/icon" android:label="#string/app_name" android:allowBackup="true" android:theme="#style/appTheme">
<activity android:name=".NewLauncherActivity" android:label="#string/app_name_full"/>
<activity-alias
android:name="${packageName}.OldLauncherActivity"
android:targetActivity="com.stuart.android.main.NewLauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19"/>
</manifest>
build.gradle
productFlavors {
flavor1 {
packageName "com.stuart.android.flavor1"
}
flavor2 {
packageName "com.stuart.android.flavor1"
}
flavor3 {
packageName "com.stuart.android.flavor1"
}
flavor4 {
packageName "com.stuart.android.flavor1"
}
}

As You use Gradle to set the "packageName" (or "applicationId"), You may try
android:name="com.stuart.android.main.NewLauncherActivity"
instead of
android:name=".NewLauncherActivity"
in line 7 of Your Manifest

Related

Manifest merger failed targeting Android 12 [duplicate]

This question already has answers here:
android:exported needs to be explicitly specified for <activity>. Apps targeting Android 12 and higher are required to specify
(35 answers)
Closed 7 months ago.
Using Android Studio 4.2.1, after changing sdk target to Android 12 in my build.gradle file, I am getting a Manifest merger failed with multiple errors, see logs error.
The errors shown in the Merged Manifest tab are as follows:
Merging Errors:
Error: Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. My_App.app main manifest (this file)
Error: Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. My_App.app main manifest (this file)
Error: Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. My_App.app main manifest (this file)
However the android:exported tag is already applied in my AndroidManifest.xml file. I only have one activity. No services or broadcast receivers. See below:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.mydomain.myapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name="com.mydomain.myapp.MyApplication"
android:allowBackup="false"
tools:replace="allowBackup"
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="com.mydomain.myapp.ui.MainActivity"
android:exported="true">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="preloaded_fonts"
android:resource="#array/preloaded_fonts" />
</application>
</manifest>
My build.gradle(:app) file:
android {
compileSdkVersion("android-S")
buildToolsVersion "30.0.3"
defaultConfig {
...
minSdkVersion 23
targetSdkVersion("S")
...
}
Any idea how I could resolve this issue?
The issue was caused by 3 activities missing the android:exported attribute in the androidx.test:core library version 1.3.0. Upgrading to version 1.4.0-beta01 fixed the issue.
If you are getting errors after targeting Android 12, the easiest way to debug this is to:
downgrade to a prior sdk version
rebuild project
after a successful build, open your project's AndroidManifest.xml.
at the bottom of the window, click on the Merged Manifest tab
look for any <activity> that includes an <intent-filter> tag and is missing the android:exported attribute
If you want to make sure these activities are the issue, add them directly to your project's AndroidManifest.xml file with the missing android:exported attribute added and try rebuilding the project.
So if <activity android:name="com.domain.ProblemActivity"> is missing the android:exported attribute, add it to your AndroidManifest.xml file like so:
<activity
android:name="com.domain.ProblemActivity"
android:exported="true" >
Rebuild targeting Android 12 and if it works, then you found the bug!
Thanks #MikePenz for pointing me in the right direction.
If your app targets Android 12 or higher and contains activities, services, or broadcast receivers that use intent filters, you must explicitly declare the android:exported attribute for these app components. In order to solve this we need to follow these steps:
We need to locate the AndroidManifest.xml in the main folder.
android>app>src>main>AndroidManifest.xml
We have to add android:exported="" and set a boolean value inside these quotation marks. Now you might ask when do I need to add android:exported="true" or android:exported="false" to the activities, services, or broadcast receivers that use intent filters.
If the app component includes the LAUNCHER category, set android:exported to true. In most other cases, set android:exported to false.
This is an example of how it should look like in your AndroidManifest.xml
<service android:name="com.example.app.backgroundService"
android:exported="false">
<intent-filter>
<action android:name="com.example.app.START_BACKGROUND" />
</intent-filter>
</service>
You can check out more info about this topic by following this link:
Safer component exporting for Android 12
If you upgrade your android studio to Bumblebee 2021.1.1.
The below changes are required to do:
Step 1: Your targetSdkVersion must be 30 or higher
Step 2: Update your appcompat library to implementation 'androidx.appcompat:appcompat:1.4.1'
Step 3: In the AndroidManifest file add android:exported = true to your activity launcher.
I had this issue, find it by:
if there's any activity, service, receiver, or provider that does not have exported attribute in your AndroidManifest file then add the below attribute in that activity, service, receiver, or provider
android:exported="false or true"
I had my Activity setup correctly with 'exported=true' and still had the following issue:
Installation failed due to [...] androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity: Targeting S+ (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present
So I came across this Github post, which could explain why this happens, and applied the workaround yogurtearl suggests and it worked for me.
https://github.com/android/android-test/issues/832
It basically goes like this:
As a workaround, putting this in the app/src/debug/AndroidManifest.xml it will force the these to launch in the same test process.
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity"
android:exported="true"
android:theme="#android:style/Theme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
android:exported="true"
android:theme="#android:style/Theme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyFloatingActivity"
android:exported="true"
android:theme="#android:style/Theme.Dialog" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
And added the 'exported=true' to them.
Don't forget to put it also into service tag
<service
android:name=".service.MyIME"
android:exported="true"
android:permission="android.permission.BIND_INPUT_METHOD">
<meta-data
android:name="android.view.im"
android:resource="#xml/method" />
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
</service>
Cleaning and rebuilding the project worked for me
If you're using DexGuard you should update to the latest version which is 9.2.11 (19-01-2022) at the moment.
Quote from the release notes:
Add default configuration for keeping the exported attribute as required by applications targeting Android 12.
As specified in the following link-
https://developer.android.com/about/versions/12/behavior-changes-12#exported ,the components of android that use intent filters must explicitly define component exporting, failing to which your app can't be installed on a device that runs on Android 12 or higher. The app components include activities, services, broadcast receivers and content providers.
If the app component includes the LAUNCHER category, set android:exported to true. In most other cases, set android:exported to false.
Even after setting the android:exported tag, if you are facing the Manifest Merger failed issue, then check all the libraries that you are using in your app. Open the external libraries in the project view of the Android Studio and try to check all the manifests files of the libraries that you have included in your project. Any one of those libraries might have not updated according to Android 12. So if you find any manifest file of the library with exported tag missing, try to edit the file and add this tag there too. Hope that could help in removing Manifest Merger Error.

Installation failed with message "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"

So I was doing some refactoring of package names in my project and now i'm no longer able to install my app. Right around the same time that I updated to the most current version of android studio. I believe that may be the problem because I think i did the refactoring before the upgrade, I just don't remember 100%
Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dodgingfire" >
<application
android:allowBackup="true"
android:icon="#mipmap/dodging_fire_icon"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".gamemain.GameMainActivity"
android:label="#string/app_name"
android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
This is how I have my packages organized
http://prntscr.com/gcrw99
This is the full error message when I try to run my app
Installation failed with message Failed to finalize session : INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: Invalid manifest package: must have at least one '.' separator.
It is possible that this issue is resolved by uninstalling an existing version of the apk if it is present, and then re-installing.
WARNING: Uninstalling will remove the application data!
Do you want to uninstall the existing application?
Even when I accept to delete the existing application, It still gives me an error and doesn't install my app let alone run it.
The package name in your source manifest file is not actually the one that ends up in the APK being installed. During manifest merging process, the final package name is based on the applicationId value in your app's build.gradle file.
As the error message says, you need at least one . in the package name.
Other reasons for INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME can be found in PackageParser#validateName() source.

Android Studio two flavors with different manifest files

I'm having issues with defining two different manifest files for my flavors in Android Studio. This is my current project structure:
The AndroidManifest.xml in the free flavor looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.example.package">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>
The AndroidManifest.xml in the main flavor has no uses-permissions, but contains the rest of the manifest code that is shared between all flavors.
The AndroidManifest.xml in the pro flavor looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.example.package">
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
</manifest>
build.gradle defines the two flavors like
productFlavors {
free {
applicationId 'se.example.package.free'
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName '1.0'
}
pro {
minSdkVersion 14
applicationId 'se.example.package.pro'
targetSdkVersion 21
versionCode 2
versionName '1.1'
}
}
The result that I am expecting is that the different flavors defines different uses-permissions. This is not the case. The result is currently that the both flavors only defines the <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> as defined in AndroidManifest.xml in the pro flavor.
I have tried:
Clean project
Rebuild project
Restart Android Studio
Sync gradle
But without success. How am I to fix this? Any help is appreciated.
EDIT 1
I changed the location of each flavors AndroidManifest.xml file from each of the res folders to free and pro folder. The result of this:
Pro flavor shows Licence permission as expected.
Free flavor shows permissions from both AndroidManifest.xml
files, License and network permissions (Should be only network)
This feels like an issue of project structure. What to make of this?
EDIT 2
I pulled the merge reports as Commonsware hinted, these are the reports regarding uses-permissions
Free:
uses-permission#com.android.vending.CHECK_LICENSE
ADDED from qwknoteGIT:licencing-library:unspecified:26:5
android:name
ADDED from qwknoteGIT:licencing-library:unspecified:26:22
Pro:
uses-permission#com.android.vending.CHECK_LICENSE
MERGED from qwknoteGIT:licencing-library:unspecified:26:5
Tech background:
on this link it explains the techniques and parameters that can be use for manifest merging: https://developer.android.com/studio/build/manage-manifests#merge_rule_markers
One in specific is the tools:node that points out how certain XML nodes on the manifest should behave whilst merging.
Solution:
to achieve some permisions in one and different in other manifest, add ALL permissions you need to the main and in the flavours manifest remove the ones you don't need, like the example below:
free remove the check license
<uses-permission
android:name="com.android.vending.CHECK_LICENSE"
tools:node="remove"/>
Your problem is coming from a library, not your flavors. Specifically, qwknoteGIT:licencing-library is requesting CHECK_LICENSE.
If you are not using that library in all flavors, use a flavored compile statement (e.g., proCompile) to only use that library in that flavor.
If you are using the library for all flavors, but feel confident that you do not need the permission in one flavor, that's where a tools:node attribute can be used, in the flavor's manifest, to block out that permission supplied by the library.
And the manifest merger report is your friend. :-)
This should solve the problem, at least. I find it useful in specifying the exact manifest to use for each variant. Cheers! It explicitly directs to the manifest file under each variant folder.
android {
productFlavors {
prod {
manifest.srcFile "prod/AndroidManifest.xml"
}
dev {
manifest.srcFile "dev/AndroidManifest.xml"
}
}
...
}
Specify your Manifest exclusively under sourceSets, In your App build.gradle
android {
productFlavors {
bizdartFlavourNoCallLog {
minSdkVersion 16
applicationIdSuffix '.bizdart'
targetSdkVersion 26
dimension "tier"
sourceSets {
main {
manifest.srcFile "src/bizdartFlavourNoCallLog/AndroidManifest.xml"
}
}
copy {
from 'src/bizdartFlavourNoCallLog/'
include '*.json'
into '.'
}
}
}
}
See https://developer.android.com/studio/build/manifest-merge with param tools:node="merge"
High priority manifest (Free):
<activity android:name="com.example.ActivityOne"
android:screenOrientation="portrait"
tools:node="merge">
</activity>
Low priority manifest (Main):
<activity android:name="com.example.ActivityOne"
android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Merged manifest result:
<activity android:name="com.example.ActivityOne"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
You should change your code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.example.package">
for:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.your.appid">
I encountered the same problem, and I found that it was because I put "pro" and "tree" flavor folder under the lib project, and the problem was solved after I move the flavors folder under the app project

Customize AndroidManifest in different build types

I want to customize AndroidManifest in different build types. For example in debug mode I just want an Activity to be exported.
Assume main manifest:
/main/AndroidManifest.xml
<application>
<activity
android:name="com.example.MainActivity" />
</application>
Debug manifest:
/debug/AndroidManifest.xml
<application>
<activity
android:name="com.example.MainActivity"
android:exported="true" />
</application>
Example manifest (same as debug):
/example/AndroidManifest.xml
<application>
<activity
android:name="com.example.MainActivity"
android:exported="true" />
</application>
In the debug manifest I get Duplicate registration for activity com.example.MainActivity
That's why I created the example build type.
/build.gradle
android {
buildTypes {
example.initWith(buildTypes.debug)
}
}
But it also doesn't work.
[AndroidManifest.xml:17, AndroidManifest.xml:4] Trying to merge incompatible /manifest/application/activity[#name=com.example.MainActivity] element:
<activity
-- #android:name="com.example.MainActivity">
--</activity>
--(end reached)
<activity
++ #android:exported="true"
++ #android:name="com.example.MainActivity">
++</activity>
I'm wondering whether this is a bug, missing feature (will be implemented in the future) or I'm doing something wrong?
I know I can provide different manifest in release and debug (without the one in /main), but I don't think this is a good solution.
EDIT:
The solution so far is to define bool in resources and use it inside main manifest.
In debug resources the bool will be true while in the release false. This solution seems much better than duplicated manifests, but the question is still actual.
As of gradle plugin 0.10 it's finally supported. More info about new manifest merger: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger
At the moment (gradle plugin 0.10) it requires this extra configuration in build.gradle
android {
useOldManifestMerger false
}
I know I can provide different manifest in release and debug (without
the one in /main), but I don't think this is a good solution.
Unfortunately, there's a limitation in the merging of manifests where you can't define the same thing (Activity, Service, Receiver, etc.) in the main manifest and the build type manifest. The solution is to define only the non-buildtype specific stuff in the main manifest and everything else in the build type manifests.

Android Studio installs an APK for each module

I have an project, build with Gradle in Android Studio v 0.3.2.
My project has dependencies to two other modules(android library). The project structure is well defined with build.gradle files.
The problem is... when i run the project on an Android device, i get installed 3 apk's on my device. One is the main project(the only right one) and the other two are from the imported modules(theese two i don't want to get installed).
How can i achieve this? Or what i'm doing wrong?
Project Structure:
MyLibModule
MainProject
MainProject->libraries->MyOtherModule
Where MyLibModule is at the same path as the Main project, because i also need this module in a other project.
Just to be clear: The whole project build's OK, all dependencies are OK, but why do i get 3 APK's on my device?
After a whole day struggling with this problem, i located the cause of this strange behaviour. The problem was the manifest of library module. Before i switched to Android studio i used Eclipse. And i had a testActivity declared in the manifest of the library project. Removing all test activities from the manifest's of my library modules solved the problem. Now Android Studio installs only the MainProject apk.
Some code:
The manifest of MyLibModule:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.mylibmodule"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7"/>
<application>
<activity
android:name=".TestActivity"
android:label="#string/app_name">
</activity>
</application>
</manifest>
Changed to:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.mylibmodule"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7"/>
<application>
</application>
</manifest>
....And the same for MyOtherModule.
NOTE: the empty application node must stay in the manifest, to avoid build errors.
remove the intent-filter from your library's launch activity
<application>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Changed to
<application>
<activity android:name=".MainActivity"/>
</application>
It's because your libraries are defined in their build.gradle files as being applications instead of libraries. Look for this line:
apply plugin: 'android'
and replace it with:
apply plugin: 'android-library'
You may need to make other adjustments to the buildfile as well because not everything that applies to applications can be specified in a library buildfile. See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-projects for more information.

Categories

Resources