Opening two instances of two different flavors but same code base - android

I am experiencing the following situation:
Application A is in the background, then I launch application B from the relevant icon, but A reopens.
Both flavors share most of the same code.
The problem is, both A and B opening the same MainActivity file. the MainActivity located in the main package and not inside the flavors packages. I want each flavor to open a new task for itself.
this is the current XML files:
A:
<activity
android:name="com.example.activities.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
B:
<activity
android:name="com.example.activities.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
and build.grade:
defaultConfig {
applicationId "com.example"
...
}
flavorDimensions "example"
productFlavors {
a{
dimension "example"
applicationIdSuffix ".a"
versionCode ...
versionName ...
//flavor consts
...
}
b{
dimension "example"
applicationIdSuffix ".b"
versionCode ...
versionName ...
//flavor consts
...
}
}
I was trying to switch the launchMode into a standard but it didn't do any good.
Thanks.

I had another field that wasn't mentioned:
android:taskAffinity="..."
both flavors used the same task Affinity application class, so I cut it into two separated Applications classes.

If you taskAffinity references your applicationId, it will only open as one instance. Try:
android:taskAffinity="${applicationId}"

Related

Android Studio - Activity gets destroyed when minimizing / opening new intent, but only in variants

I have a project setup with three flavors/variants. It originally was based on just one flavor, and later the latter two were added extra. The weird thing is that in the flavor (based on the original app) I can minimize the app, and reopen it without any issues. But when opening any intent or minimizing the app with the other flavours, the last activity is always destroyed from the stack.
At the moment I minimize, the onDestroy() of the activity gets called straight away.
This is how my manifest is built up:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxxxxxxxxxx">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_label"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.NoActionBar"
android:usesCleartextTraffic="true">
<activity
android:name=".SubMenuActivity"
android:exported="false"
android:label="Submenu"
android:parentActivityName=".WebActivity"
android:theme="#style/Theme.AppCompat.DayNight.DarkActionBar"
/>
<activity
android:name=".login.LoginActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation"
android:label="#string/title_activity_login"
android:launchMode="singleTop"
android:noHistory="false"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="xxxxx"
android:pathPattern="xxxx"
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation"
android:launchMode="singleTop"
android:noHistory="false"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".WebActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation"
android:launchMode="singleTop"
android:noHistory="false"
android:screenOrientation="portrait" />
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="#string/fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/fileprovider" />
</provider>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_action_name" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
</application>
</manifest>
And this is how (most of) my gradle.app looks like:
android {
..
..
flavorDimensions "version"
compileSdkVersion 31
defaultConfig {
applicationId "xxxxxx"
minSdkVersion 26
targetSdkVersion 31
versionCode 203
versionName "2.0.3"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
productFlavors {
janbarn {
dimension "version"
applicationIdSuffix ".flavor1"
}
shapeshifterzz {
dimension "version"
applicationIdSuffix ".flavor2"
}
dwleven {
dimension "version"
applicationIdSuffix ".flavor3"
}
}
buildTypes {
release {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
productFlavors.flavor1.signingConfig signingConfigs.flavor1
productFlavors.flavor2.signingConfig signingConfigs.flavor2
productFlavors.flavor3.signingConfig signingConfigs.flavor3
}
}
sourceSets {
janbarn {
res {
srcDirs 'src/flavor1/res'
}
java {
srcDirs 'src/flavor1/java'
}
}
shapeshifterzz {
res {
srcDirs 'src/flavor2/res'
}
java {
srcDirs 'src/flavor2/java'
}
}
dwleven {
res {
srcDirs 'src/flavor3/res'
}
java {
srcDirs 'src/flavor3/java'
}
}
}
compileOptions{
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
lint {
checkReleaseBuilds false
}
buildFeatures {
viewBinding true
}
}
I have anonymized some of the names since im running this project for a friend of mine.
I hope someone can help me with this one, might safe me some more hours of digging!
I have tried to use different launchmodes, tried the persistent state and alwaysRetainTaskState but nothing seems to help. And again in flavor1 there is no problem.

How to add different values of string resource for different flavors?

I'm an iOS developer who is trying to make some small changes on android side but with no clue of how to achieve them. My goal is to implement Facebook SDK inside the app, official documentation says:
In /app/res/values/strings.xml add new string element:
<string name="facebook_app_id">Facebook App ID</string>
Then add in AndroidManifest.xml file new meta-data like below:
<application android:label="#string/app_name" ...>
...
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/facebook_app_id"/>
...
</application>
All is understood but my problem is that I have few product flavors based on which I build at the end stand alone apps, for each I have different Facebook App ID. I would appreciate any kind of help. Thanks!
You can create multiple build types or product flavors inside the app-level build.gradle file and then define different strings for each build variant like this
buildTypes {
prod{
resValue "string", "facebook_app_id", "your app id"
}
dev {
resValue "string", "facebook_app_id", "your app id"
}
}
Now you can access this string inside manifest
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/facebook_app_id"/>
There are many ways. But as you already define multiple flavour in build.gradle in app level then you can define the string over there like this
android {
buildTypes {
flavour1 {
buildConfigField "String", "facebook_app_id", "\"first facebook id 1\""
}
flavour2 {
buildConfigField "String", "facebook_app_id", "\"first facebook id 2\""
}
}
}
It automatically initialise the facebook_app_id to the build when you are creating the build of the flavour.
Happy Coding :)
In build.gradle :
productFlavors {
appDev {
applicationId 'com.android.dev'
}
appTest {
applicationId 'com.android.test'
}
}
flavorDimensions "default"
Inside src folder:
create folder with flavors name
-src
-appDev(folder)
-java(folder)
-res(folder)
-values(folder)
-appTest(folder)
-java(folder)
-res(folder)
-values(folder)
inside values folder you can create strings.xml each folder act as different flavor
you need to pass your facebook app_id in the string files.
<string name="facebook_app_id">35166120881***</string>
<string name="fb_login_protocol_scheme">fb35166120881****</string>
...
<activity android:name="com.facebook.FacebookActivity"
android:configChanges=
"keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="#string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="#string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
...
</application>
Important this
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id"/>

Android: Element Activity is now allowed here

In the code below Android Studio shows me
"Element activity is now allowed here"
when I hover over activity tag, and the app doesn't launch the activity which is the default one, I tried clean project, rebuild project then restarted Android Studio, I tried invalidate cashes / restart, and the problem still exist, how to fix this?
<activit
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activit>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.blabla.testapp1"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.0'
}
In your manifest i see you wrote activit instead of activity. Make it okey
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Android split ActionBar not working

I'm new with android ... i want to have a simple activity with a bottom action Bar in all tutorials it's mentionned that there is a way with
android:uiOptions=”splitActionBarWhenNarrow”
but it does not work on tablet or smal device even when i added
<meta-data android:name="android.support.UI_OPTIONS"
android:value="splitActionBarWhenNarrow" />
</activity>
this is my manifest.xml
<application
android:allowBackup="true"
android:icon="#drawable/logo"
android:label="#string/app_name"
android:theme="#style/AppTheme"
>
<activity
android:name=".launchActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:uiOptions="splitActionBarWhenNarrow"
android:name=".MainActivity"
>
<meta-data android:name="android.support.UI_OPTIONS"
android:value="splitActionBarWhenNarrow" />
</activity>
<activity
android:name=".DisplayMessageActivity"
android:label="#string/title_activity_display_message" >
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
build file
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "xxxxxxx"
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Android 5.0's default theme (Theme.Material) does not support the split action bar. Neither does the appcompat-v7 action bar backport anymore, though it used to.
Your options are either to switch to theme based off of Theme.Holo, put your own bar at the bottom of the screen (e.g., a Toolbar), or simply redesign your UI to avoid the split action bar.
I'm fully agree with #CommonsWare answer.
I just add a note.
If you build your app only for Lolipop(5.0) or higher(for now) the action bar may be represented by any Toolbar widget within the application layout. You can align components(also split them) inside since you are want.

How do I change the AndroidManifest.xml file based on build variants?

I have an app with multiple build variants. The variants are used to build versions of the same app for different companies. So, I have several different variants that build different apps:
com.acme.app1
com.schmoe.app2
com.yop.app3
etc...
The build.gradle file handles this very well:
productFlavors {
app1 {
applicationId "com.acme.app1"
}
app2 {
applicationId "com.schmoe.app2"
}
app3 {
applicationId "com.yop.app3"
}
}
Here's my problem. I am integrating Dropbox into my apps. The AndroidManifest.xml file must be changed for each variant to include the appropriate app key (stored in my string file). Dropbox has the following addition to the manifest file:
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard">
<intent-filter>
<!-- Change this to be db- followed by your app key -->
<data android:scheme="db-abcdef" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Each build variant needs to change the following line:
<data android:scheme="db-abcdef" />
to the appropriate value for each app variant. In other words, I need to replace part of the above string based on the build variant. For instance
App1
<data android:scheme="db-111111" />
App2
<data android:scheme="db-222222" />
App3
<data android:scheme="db-333333" />
The line is the same for each variant up to the text "db-".
What I need is to dynamically replace the variable portion of the string (the x values) "db-xxxxxx" with a string from my string file.
I think this can be done with gradle scripts but I'm a complete newb with gradle. HELP!
If you can help, please be very specific about what goes where since I SUCK at gradle files and scripting. Thanks in advance!
You can save the string in build.gradle too:
productFlavors {
app1 {
applicationId "com.acme.app1"
resValue "string", "my_app_key", "db-abc"
}
app2 {
applicationId "com.schmoe.app2"
resValue "string", "my_app_key", "db-def"
}
app3 {
applicationId "com.yop.app3"
resValue "string", "my_app_key", "db-ghi"
}
}
And then use it like:
<data android:scheme="#string/my_app_key" />
You can do this the same way you would modify the app name, using a string resource. In your manifest, include:
<data android:scheme="#string/db_scheme" />
Next, you add resources folders for the various build types, and in each, place a custom copy of a resource file, say res/values/flavor.xml:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="app_name">Customer 1 App</string>
<string name="db_scheme">db-111111</string>
</resources>
This will allow you to have different API keys, schemes, app-names, icons, etc. for your various flavors.
For people visiting this in 2019: You can use manifestPlaceholders per flavor.
In your case:
productFlavors {
app1 {
applicationId "com.acme.app1"
manifestPlaceholders.scheme = "db-111111"
}
app2 {
applicationId "com.schmoe.app2"
manifestPlaceholders.scheme = "db-222222"
}
app3 {
applicationId "com.yop.app3"
manifestPlaceholders.scheme = "db-333333"
}
}
and then use it in your manifest:
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard">
<intent-filter>
<!-- Change this to be db- followed by your app key -->
<data android:scheme="${scheme}" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Yet another way that is somewhat similar to Hibbem's answer:
android {
defaultConfig {
manifestPlaceholders = [schemeName: "default-scheme"]
}
...
app1 {
applicationId "com.acme.app1"
manifestPlaceholders = [schemeName: "db-111111"]
}
...
}
And in your manifest:
<intent-filter>
...
<data android:scheme="${schemeName}" />
...
</intent-filter>
More from the official docs

Categories

Resources