Fix Android Launch From Home
This documentation is a work in progress. It should suffice to fix this particular issue but additional changes are likely to be made.
Cordova and Capacitor applications, when launched on an Android device, will startup and display the webview your application is served in. However, for Auth Connect this may not be the behavior you want when a user is on the login page: you will likely want your application to return to the login page.
To make this behavior possible you'll need to alter your Cordova or Capacitor application using the following instructions.
Capacitor
Launching a Capacitor app on an Android device typically initiates the display of your application's content in a webview. However, if the user is in the process of authentication and leaves the app it might not display the login page in the same state when the user returns. To fix this behavior you would want the app to direct users back to the login page instead of the application's content in such scenarios. To achieve this, specific modifications are necessary, as outlined in the following steps.
Go to your Capacitor Android project and navigate to the directory that contains your application's package. Your path will be something like android/app/src/main/java/io/ionic/starter/
. However, the end of the path will reflect your unique bundle ID.
Create a new Java file in this folder named LauncherActivity.java
.
Copy and paste the provided code into the new activity file (LauncherActivity.java
).
Replace io.ionic.starter
with your project's identifier.
Navigate to the AndroidManifest.xml
file which is located at the following file path android/app/src/main/
and locate the activity section.
Update the AndroidManifest.xml
to set the new Activity as the launcher activity. Add an intent-filter
to LauncherActivity
to define it as the launcher.
Remove the intent-filter
on the MainActivity
that previously defined it as the launcher.
On the MainActivity
change exported to false
and make sure to keep launchMode
as singleTask
.
Copy and paste the provided code into the new activity file (LauncherActivity.java
).
Replace io.ionic.starter
with your project's identifier.
Navigate to the AndroidManifest.xml
file which is located at the following file path android/app/src/main/
and locate the activity section.
Update the AndroidManifest.xml
to set the new Activity as the launcher activity. Add an intent-filter
to LauncherActivity
to define it as the launcher.
Remove the intent-filter
on the MainActivity
that previously defined it as the launcher.
On the MainActivity
change exported to false
and make sure to keep launchMode
as singleTask
.
Be sure to run npx cap sync
after applying these changes.
To test that you have correctly applied these changes:
- Launch your application with an Android device.
- Go to the login page.
- Return to the home screen of your Android device.
- Launch your app again by pressing the icon.
- Your application should now open displaying the login page in the state it was left in.
Cordova
There are a few steps to apply on a Cordova project.
- Create a
scripts
folder in your project. - Create a file called
LaunchActivity.java
in thescripts
folder and paste below in the contents. - Replace the line
package io.ionic.starter
with the id from yourconfig.xml
_16package io.ionic.starter;_16_16import android.content.Intent;_16import android.os.Bundle;_16import androidx.appcompat.app.AppCompatActivity;_16_16public class LauncherActivity extends AppCompatActivity {_16 @Override_16 protected void onCreate(Bundle savedInstanceState) {_16 super.onCreate(savedInstanceState);_16 Intent i = new Intent(this, MainActivity.class);_16 i.replaceExtras(this.getIntent());_16 startActivity(i);_16 finish();_16 }_16}
- Create a file called
update-launcher.js
in thescripts
folder and paste the below file - Set the path of
LAUNCHER_DESTINATION
inupdate-launcher.js
to match your id fromconfig.xml
_167var ANDROID_PROJECT_ROOT = 'platforms/android/app/src/main';_167var LAUNCHER_DESTINATION = 'platforms/android/app/src/main/java/io/ionic/starter';_167var LAUNCHER_SOURCE = 'scripts/LauncherActivity.java';_167var fs = require('fs');_167var path = require('path');_167var xml2js = require('xml2js');_167_167function copyJavaLauncher() {_167 return new Promise((resolve, reject) => {_167 fs.access(LAUNCHER_DESTINATION, (err) => {_167 if (err) {_167 reject('INVALID LAUNCHER DESTINATION');_167 return;_167 }_167 copyFile(LAUNCHER_SOURCE, path.join(LAUNCHER_DESTINATION, 'LauncherActivity.java'));_167 });_167 });_167}_167_167function copyFile(src, dest) {_167 return new Promise((resolve, reject) => {_167 let readStream = fs.createReadStream(src);_167_167 readStream.once('error', (err) => {_167 reject(err);_167 });_167_167 readStream.once('end', () => {_167 resolve('done');_167 });_167_167 readStream.pipe(fs.createWriteStream(dest));_167 });_167}_167_167function readManifest() {_167 return new Promise((resolve, reject) => {_167 fs.readFile(path.join(ANDROID_PROJECT_ROOT, 'AndroidManifest.xml'), 'utf-8', (err, input) => {_167 if (!!err) {_167 reject(err);_167 } else {_167 resolve(input);_167 }_167 });_167 });_167}_167_167function writeManifest(data) {_167 return new Promise((resolve, reject) => {_167 fs.writeFile(path.join(ANDROID_PROJECT_ROOT, 'AndroidManifest.xml'), data, (err) => {_167 if (!!err) {_167 reject(err);_167 } else {_167 resolve();_167 }_167 });_167 });_167}_167_167function convertToJson(input) {_167 return new Promise((resolve, reject) => {_167 xml2js.parseString(input, (err, result) => {_167 if (!!err) {_167 reject(err);_167 } else {_167 resolve(result);_167 }_167 });_167 });_167}_167_167function convertToXML(input) {_167 return new Promise((resolve, reject) => {_167 let builder = new xml2js.Builder();_167 let xml = builder.buildObject(input);_167 resolve(xml);_167 });_167}_167_167function removeLegacyActivityIntent(data) {_167 return new Promise((resolve, reject) => {_167 let applications = data.manifest.application;_167 if (!applications) {_167 reject();_167 return;_167 }_167 applications.forEach((application) => {_167 if (!!application.activity) {_167 application.activity.forEach((activity) => {_167 if (activity['intent-filter']) {_167 activity['intent-filter'].forEach((intent, idx) => {_167 let shouldRemove = false;_167 if (intent.action) {_167 intent.action.forEach((action) => {_167 if (action['$']['android:name'].includes('MAIN')) {_167 shouldRemove = true;_167 }_167 });_167 }_167 if (shouldRemove) {_167 delete activity['intent-filter'][idx];_167 }_167 });_167 }_167 });_167 }_167 });_167 resolve(data);_167 });_167}_167_167function addLauncherActivityIntent(data) {_167 return new Promise((resolve, reject) => {_167 let applications = data.manifest.application;_167 if (!applications) {_167 reject();_167 return;_167 }_167 applications.forEach((application) => {_167 if (typeof application.activity === 'undefined') {_167 application.activity = [];_167 }_167 application.activity.push({_167 $: {_167 'android:name': 'LauncherActivity',_167 'android:label': '@string/app_name',_167 'android:theme': '@android:style/Theme.DeviceDefault.NoActionBar',_167 'android:exported': 'true',_167 },_167 'intent-filter': [_167 {_167 action: {_167 $: {_167 'android:name': 'android.intent.action.MAIN',_167 },_167 },_167 category: {_167 $: {_167 'android:name': 'android.intent.category.LAUNCHER',_167 },_167 },_167 },_167 ],_167 });_167 });_167 resolve(data);_167 });_167}_167_167module.exports = function (context) {_167 return new Promise((resolve, reject) => {_167 readManifest()_167 .then((input) => convertToJson(input))_167 .then((data) => removeLegacyActivityIntent(data))_167 .then((data) => addLauncherActivityIntent(data))_167 .then((data) => convertToXML(data))_167 .then((input) => writeManifest(input))_167 .then(() => copyJavaLauncher())_167 .then((data) => {_167 resolve('done');_167 })_167 .catch((err) => {_167 console.log(err);_167 reject('done');_167 });_167 });_167};
- Next step is to install xml2js with:
_10npm install xml2js --save-dev
Finally update config.xml
by adding the following line underneath <platform name="android">
:
_10<hook src="scripts/update-launcher.js" type="after_platform_add" />
This script will run when you add the Android platform is added so to test it you can run:
ionic cordova platform remove android
ionic cordova platform add android
Be sure that the package line in LaunchActivity.java
and the LAUNCHER_DESTINATION
match what is used for your id
in config.xml
.
Testing
To test that you have correctly applied these changes:
- Launch your application with an Android device
- Go to the login page
- Return to the home screen of your Android device
- Launch your app again by pressing the icon
- Your application should now open displaying the login page in the state it was left in