I use deep links in my app.
This is my activity in manifest
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar.Launcher">
<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:host="app.mydomain.com"
android:pathPrefix="/prefix"
android:scheme="https" />
</intent-filter>
</activity>
And this is how I get deep link
Uri uri = getIntent().getData();
After I'm done with handling deep link and some other logic in MainActivity, I navigate user to other activity, and finish MainActivity.
The problem is, in certain scenario, I got deep link delivered over and over again. This is scenario whet problem happens:
At moment I click link, my app is not in memory or closed by tap on system back button.
After link handled in my app, I close app with system back button.
Then I open app by clicking on it's preview (not launcher icon) in menu with all in memory apps (opens by clicking on one system button on my phone). And deep link is delivered again.
The problem is, when link delivered I can't identify, is it this particular problematic case scenario, and I should ignore the link, or is user actually clicked the link, and I should handle it.
Saving the link in static variable to check if is it the same link would be not good, cause user may click the same link again to review the same data.
The problem also persists with Firebase Dynamic Links.
My phone runs on Android 12 (api level 31), Samsung S21
Found a solution, thanks to this answer
I check if activity was launched from history using this method, and if true, then I ignore deep link
private boolean isActivityLaunchedFromHistory() {
return getIntent().getFlags() ==
(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
}
Related
On Android 8.0+ only, when opening my app with a deep link (clicking on the push notification with a URI attached) the app will open my entrypoint activity and then open up the deep linking activity.
This is not seen on Android lower than 8.0. In that case, it will open the deep linking activity directly and it will not open the splash screen activity.
Unfortunately, the way the app works is that when the entrypoint activity is called (it is a splash screen) it will then move to another activity. This makes it highly unreliable to open the deep link when the app was hard closed because when the deep link activity runs (approximately 80ms after the splash screen runs) the app is already transitioning to the next activity which may cancel out the deep link entirely.
To circumvent this, I've tried to handle the deep linking inside of the splash activity with setting the launchMode to singleTask, singleTop and singleInstance. Unfortunately, none of those worked.
I've managed to solve this issue by using a timer by holding the splash screen for 200ms longer than usual but that solution seems dirty and doesn't seem extremely reliable for all devices.
Here is the my splash activity and the deep linking activity in the manifest
<activity
android:name=".activities.LauncherActivity"
android:excludeFromRecents="true"
android:taskAffinity="${launcherAffinity}"
android:theme="#android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.ParseDeepLinkActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data
android:host="*"
android:scheme="com.deeplink" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</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:scheme="https"
android:host="deep.link.net"
android:pathPrefix="/mobile" />
</intent-filter>
</activity>
This is my launcher activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
startActivity(
new Intent(this, LoginActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
finish();
}
I would like it if I can just open the deep link activity directly as it does on lower than 8.0. I tried searching for any documentation if deep linking has changed in 8.0+ but there was nothing I could find.
Solved!
The issue was in UrbanAirship. Our class that extends AirshipReceiver in the method onNotifactionOpened was default returning false which means it will also launch the launcher activity. Why this causes an issue in only 8.0+ I am not too sure. Here is how I resolved it
#Override
protected boolean onNotificationOpened(#NonNull Context context, #NonNull NotificationInfo notificationInfo) {
Map<String, ActionValue> notificationActions = notificationInfo.getMessage().getActions();
// Return false here to allow Urban Airship to auto launch the launcher activity
try{
return notificationActions.containsKey("^d");
}catch(Exception e){
return false;
}
}
^d is the default key for deep link actions as listed here
https://docs.airship.com/reference/libraries/android/latest/reference/com/urbanairship/actions/DeepLinkAction.html
I don't know if it's really understandable.
When i'm clicking on a llink in a mail, I can open this link with my application and that's perfeclty what I want.
<intent-filter>
<data android:scheme="https" android:host="xxx.xxx.com"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
BUT
When i'm opening my application like that, and I check the opened application, I see that my application is "inside" Gmail task, like that
But, when i'm opening the link with Chrome for exemple, Chrome is opening in his own task, like that
How can my application open in her own task and NOT inside Gmail's one ?
you have to set a specific andorid:launchMode to your activity:
android:launchMode="singleTask"
or
android:launchMode="singleInstance"
placed in the declaration of your activity in the AndroidManifest.xml will do it.
take a look also at this article that explain how android handles tasks and activities
Phonegap Application lunching Problem
it is manifest file:
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<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:scheme="cedemo" android:host="com.example.shcema.MainActivity"/>
</intent-filter>
</activity>
it is my main activity:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}}
But when I click "Launch Application" link then i get this alert.
please, help me any one.
You missed CATEGORY_BROWSABLE in your intent-filter.
Quote from Android Docs:
Activities that can be safely invoked from a browser must support this category. For example, if the user is viewing a web page or an e-mail and clicks on a link in the text, the Intent generated execute that link will require the BROWSABLE category, so that only activities supporting this category will be considered as possible actions. By supporting this category, you are promising that there is nothing damaging (without user intervention) that can happen by invoking any matching Intent.
So your intent-filter must be like:
<intent-filter>
<data android:scheme="cedemo" android:host="com.example.shcema.MainActivity"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
See more at : Make a link in the Android browser start up my app?
This won't work. because how Android can know which App I've start on this custom URI call?
So you first have to let the android know that a custom URI exists which can receive such calls and then whenever that custom URI is invoked by any app either native or hybrid, OS will automatically forward it to the registered app i.e. able to receive such calls.
Read this Android docs tutorial:
Allowing Other Apps to Start Your Activity
http://developer.android.com/training/basics/intents/filters.html
Here is an example how one app can call other app. Launch an application from another application on Android
And here is custom plugin which makes easier to open another app from the Cordova/phonegap App.
https://github.com/lampaa/org.apache.cordova.startapp
So I have such tricky thing declared in Manifest to be able to start my app from a browser:
<activity android:name=".BrowserIntentCallBackActivity"
android:noHistory="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:host="*"
android:scheme="trickyapp" />
</intent-filter>
</activity>
this workds ok and starts my BrowserIntentCallBackActivity as expected. If my app wasnt previously started then finishing the BrowserIntentCallBackActivity returns user back to browser and its fine.
However if my app was previuosly started and is running on background finishing the BrowserIntentCallBackActivity returns user to previuos activity of my app. But I want to send user back to browser where he/she clicked the very special link and from where my BrowserIntentCallBackActivity was launched by intent. And I dont want ot kill my running app.
How to achieve this?
Try setting the launch mode of your activity:
https://developer.android.com/guide/topics/manifest/activity-element.html#lmode
I believe the correct mode for your task will be "singleTask" or maybe "singleInstance", although I have limited experience with those so you will have to experiment to be sure.
I've developed an Android Application. I've defined an intent-filter so that my app is used to view some links:
<intent-filter>
<data
android:host="my_url.com"
android:pathPrefix="/some_prefix/"
android:scheme="http" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
When I open one link like "my_url.com/some_prefix", my app appears on the selector and, if chosen, its open to display the link.
However, my Activity is opened attached to the application that lauched it. Lets say, for example, that the link is displayed in a WhatsApp message, after opening the link my app is displayed. If I try to open WhatsApp again, my Activity is displayed, instead of WhatsApp.
How can I detach my Application from the Application that called it?
Your activity is being opened in the current 'task', which is the WhatsApp task.
What you are wanting is for your app to be opened in a new task.
There is a flag you can set on your activity in the manifest:
android:launchMode="singleTask"
This will tell android to open your activity in another task.
Read more about tasks here