so what I'm trying to achieve is the following:
In App 1, I'm loading a website in a CustomTab, this website jumps to App 2 via App Links. In App 2, after performing a task, I want to jump back to App 1, where the CustomTab still needs to be open as it needs to do some processing. I have this working where I jump back to App 1 via the package name, but I need to get it working via App Links as well.
However, what currently happens is that the CustomTab seems to get closed when I jump back via App Links. My first thought is that I'm not retaining the app / starting the activity correctly.
AndroidManifest of App 1:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.secret.package.name">
<application
android:allowBackup="true"
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=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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:scheme="https"
android:host="some.secret.url" />
</intent-filter>
</activity>
</application>
</manifest>
Opening the CustomTab in App 1:
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(MainActivity.this, Uri.parse(url));
Code in App 2 to jump back:
private void performAppSwitch() {
Intent intentWithURI = new Intent(Intent.ACTION_VIEW, Uri.parse(APP_LINKS_URL));
PackageManager packageManager = context.getPackageManager();
if (intentWithURI.resolveActivity(packageManager) != null) {
intentWithURI.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentWithURI);
} else {
Intent intentWithPackageID = packageManager.getLaunchIntentForPackage(PACKAGE_NAME);
if (intentWithPackageID != null) {
List<ResolveInfo> activities = packageManager.queryIntentActivities(intentWithPackageID, 0);
boolean isIntentSafe = !activities.isEmpty();
if (isIntentSafe) {
intentWithPackageID.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentWithPackageID);
}
}
}
}
Any ideas as to why it's working when I switch via package name but not when I switch via App Links?
I have tried every possible variant of launchMode
The issue was that the CustomTab was starting an activity of its own, and I had to make sure that App 1 did not redraw.
So in App 1, adding the following to onCreate of my main activity would do the trick:
if (!isTaskRoot()) {
finish();
return;
}
Related
I'm developing an app that opens other apps with intents and it works perfectly, but now I need to open a specific activity and I don't know if it's even possible.
already installed both app and I am not able to open specific activity from my app.
btnCallActivity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Intent intent = new Intent();
intent.setClassName("com.rayvatapps.flatplan", "com.rayvatapps.flatplan.LoginActivity");
intent.putExtra("WEBVIEW_URL", "https://google.com/");
startActivity(intent);
} catch (Exception e) {
Toast.makeText(mContext, "oops...app is not found", Toast.LENGTH_SHORT).show();
}
}
});
Manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rayvatapps.flatmaps">
<application
android:allowBackup="true"
android:exported="true"
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=".LoginActivity"
android:label="Other App"
android:exported="true">
<intent-filter>
<action android:name="com.rayvatapps.flatplan.app.LoginActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
i am getting following error
Error: No Activity found to handle Intent { act=com.rayvatapps.flatplan.app.LoginActivity }
E/Error: Permission Denial: starting Intent { cmp=com.rayvatapps.flatplan/.LoginActivity (has extras) } from ProcessRecord{4310b06 9701:com.rayvatapps.appdemotest/u0a384} (pid=9701, uid=10384) not exported from uid 10378
Any help will be highly appreciated.
In Manifest.xml of Second Apps Activity add Intent Filter -> android.intent.category.DEFAULT
<activity
android:name="com.myapp.ActivityName"
android:exported="true">
<intent-filter>
<action android:name="com.demo.any_name" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Then from your app
Intent launch = new Intent("com.demo.any_name");
startActivity(launch);
Your package and class names do not match. Based on the manifest of the app you want to start, you need to change this:
intent.setClassName("com.rayvatapps.flatplan", "com.rayvatapps.flatplan.LoginActivity");
into this:
intent.setClassName("com.rayvatapps.flatmaps", "com.rayvatapps.flatmaps.LoginActivity");
You also don't need the <intent-filter> on the Activity in the app you are trying to start, as you are using an explicit Intent to start it. If you remove the <intent-filter> make sure that you keep the android:exported="true" for the Activity, otherwise you won't be able to launch it from another application.
I have two apps. From the first, I want to launch the second one by deep linking. It works but the problem is that the second one starts inside the first one. I would like to start the second one in a new instance.
The code of the first app to open the second app:
String uri = "deeplinkTestTom://token/123456";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
The manifest of the second app:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data
android:scheme="deeplinkTestTom" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
</application>
When I try to launch Facebook app from my first app (String uri = "facebook://facebook.com/inbox";), it launch facebook in a new app and not inside my first app. So I suppose that something is missig in the manifest of my second app, but I can't find what.
What should I do ?
I believe you're talking about new Task instead of "new app".
Read Tasks and Back Stack
You need to use Intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) to start an Activity in a new Task.
For your case, use
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
I have created an Intent filter to open my application when clicking on an specified link such as "http://www.myapp.com/1234". When I click on the link I am asked to open the app, and OK, everything works well. Then, I quit from the app by clicking repeatedly in the back button until all activities are closed. But:
After launching the app again from the launcher, it receives the same Intent data than
before when I clicked the link. How do avoid it?
When I open my app from a link, ie. from WhatsApp, as I can see in the app manager, WhatsApp is the application which is opened! why?
Here is my current manifest code:
<activity
android:name="com.x.y.SplashActivity"
android:label="#string/app_name"
android:noHistory="true"
android:screenOrientation="portrait"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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:host="#string/app_host"
android:pathPrefix="/events/"
android:scheme="http" />
</intent-filter>
</activity>
and in my onCreate():
// Retrieve the Intent
Intent intentUri = getIntent();
// Check URI
Uri uri = intentUri.getData();
if (uri != null) {
// Try to extract the data
// For now, data could be a public event id, so parse it
List<String> pathSegments = uri.getPathSegments();
// Check validity
if (pathSegments.size() > 2) {
// Finally, get the public event id
String publicEventId = pathSegments.get(2);
// Set poll as responded
user.setPollEventId(publicEventId);
}
// Remove the intent to prevent further calls
setIntent(null);
}
// Open the main activity normally
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
I have two applications. The first one A has a web view with a link to another application and a timestamp.
In this web view, I have a link that opens another application B. In B, I have a button. The click on the button should take me back to app A,
without reloading it, and executing a javascript code that should populate some other fields in the web view.
As a result, App A should be brought back, timestamp should not be changed and the javascript called and fields properly populated.
The problem is if I do this scenario and I start app B from A using only StartActivity(), it doesn't work. I'm able to do A-B and B-A but my javascript is not called
because A is not called with the proper intent. In other words, when calling A from B, I should find in the intent object the action and the data that took me to A but instead the action in the intent is NULL
If in the other hand, I add a flag when starting Activity on B : FLAG_ACTIVITY_NEW_TASK. it works one time. A->B->A but after that I'm not able to call B again.
Another test I made: If I start calling B from the home screen and than A and than B. It works. So I guess it has to do with the fact that B is different if called using intent from A or from home screen.
Anyway, I couldn't make it open the app, call the js and keep the context all in the same time.
I only tried on emulator.
Here is Manifest for App A
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cgi.csb.launcher"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="12"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="#string/app_name" android:icon="#drawable/ic_launcher">
<activity android:name=".Activity1" launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:host="localhost" android:scheme="myactivity"></data>
</intent-filter>
</activity>
</application>
</manifest>
Here is the manifest for App B
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.CallerApp"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="12"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="#string/app_name">
<activity android:name=".Activity2" launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:host="dummy"
android:scheme="testintentapp"/>
</intent-filter>
</activity>
</application>
</manifest>
To call B from A :
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addCategory("android.intent.category.DEFAULT");
startActivity(intent);
return true;
}
To call A from B :
case R.id.button:
Intent intent = new Intent();
intent.setData(Uri.parse("myactivity://localhost"));
intent.putExtra("firstKeyName","FirstKeyValue");
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
finish();
break;
The code I use to differentiate when A is called from home or from App B to call the javascript
Intent intent = getIntent();
if ("myactivity://localhost".equals(intent.getDataString())) {
Log.d(TAG, "*** Call JS with action : " + intent.getAction());
_jsHandler.javaFnCall("Hardcoded params");
} else {
Log.d(TAG, "***Just call the app with action :" + intent.getAction());
}
Thanks a lot !
I am developing two android applications:
the first is a normal application with a launcher and so on
the other is a application only with a viewer activity (see the manifest):
<activity
android:name=".MyActivity"
android:icon="#drawable/icon"
android:label="#string/dropbox" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:configChanges="orientation|keyboard"
android:launchMode="singleTask" >
<intent-filter>
<data android:scheme="db-XXXXX" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The plan is, that the first application does not need internet permissions and the second is some kind of add-on to the first.
The second application should sync a file with Dropbox (with the Core API, not with the Sync API).
From my first app, I start 'MyActivity' from the second app like this:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setComponent(new ComponentName("my.package","my.package.MyActivity"));
intent.putExtra("filePath", "/myFile.txt");
startActivityForResult(intent, SYNC_REQUEST);
That works. The Activity comes up and there, if not authorized yet, the user must press a button. Then the following code will be executed
AndroidAuthSession session = buildSession();
mApi = new DropboxAPI<AndroidAuthSession>(session);
mApi.getSession().startAuthentication(MyActivity.this);
If the user does not have dropbox installed, the browser will pop up.
Now my troubles begin:
As soon as the user presses 'Accept' or 'Decline', the browser does not disappear. It stays open and MyActivity does not get resumed (onResume is not called!).
I found out, that adding
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
before starting MyActivity from my first application will solve the problem, but then I can not listen/wait for the result of MyActivity.
I am frustrated. Can anyone help me or give me some advise?
Thanks!
When you are using startAuthentication method. It will automatically start the AuthActivity. you do not need to call startActivity() explicitly. Then in onResume method of your activity write this code :
#Override
protected void onResume()
{
super.onResume();
if (if dropBoxAPI!= null && dropboxAPI.getSession().authenticationSuccessful())
{
try {
dropboxAPI.getSession().finishAuthentication();
oAuth2Token = dropboxAPI.getSession().getOAuth2AccessToken();
}
catch (IllegalStateException ie)
{
ie.printStackTrace();
}
}
}