{ "id": "167984", "key": "TIMOB-24747", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": { "id": "10000", "description": "", "name": "Done" }, "resolutiondate": "2018-08-03T17:16:48.000+0000", "created": "2017-05-30T12:11:51.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [ "android", "intents", "url-scheme" ], "versions": [ { "id": "17608", "name": "Release 6.1.0", "archived": false, "released": true, "releaseDate": "2017-05-26" } ], "issuelinks": [ { "id": "57117", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "171712", "key": "TIMOB-26075", "fields": { "summary": "Android: Refactor app resume and \"newintent\" handling", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "name": "Improvement", "subtask": false } } } } ], "assignee": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2019-01-11T03:41:25.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "I am not providing a testcase here since i think its time that Appcelerator brings forward a working testcase for the custom URL schemes because there have been so many broken examples.\r\n\r\nThere have been various issues created and (supposedly) fixed in JIRA, like TIMOB-15253, TIMOB-20490 and TIMOB-20459, but issues still seem to exist in the current build (6.1.0.GA as of speaking).\r\n\r\nPlease provide:\r\n- The absolute minimum setup for _tiapp.xml_ in order to start receiving intents through custom URL schemes\r\n- The usage and workings of \"intent-filter-new-task\" versus \"android:launchMode\".\r\n- Test this case with the app being \"resumed\" from background and \"newly created\".\r\n\r\nIf this can be created into a page for the Titanium Documentation than that would be great.\r\n\r\nThe end result should feature an application that is always a single instance, that is:\r\n- Opening an intent from the browser like _Link_ should +always+ re-use the existing instance if there is one. If not, it should open a new instance.\r\n- A splash screen should only be shown when the app is completely shut down.\r\n- In absolutely no case should there be multiple instances of the same app. In my tests i've come across multiple instances of the app after opening a custom URL. I was able to identify this due to the logging of events.\r\n\r\nBy looking at the comments of the TIMOB's mentioned above and by my own experience, I know there are still bugs regarding this functionality. Issues seem to be closed for sake of progression rather than actually fixing the issue.", "attachment": [], "flagged": false, "summary": "Android: new tasks are created upon opening a custom URL scheme", "creator": { "name": "creative_jira_user", "key": "uzbbert", "displayName": "Creative", "active": false, "timeZone": "Europe/Amsterdam" }, "subtasks": [], "reporter": { "name": "creative_jira_user", "key": "uzbbert", "displayName": "Creative", "active": false, "timeZone": "Europe/Amsterdam" }, "environment": "Ti 6.1.0.GA, Alloy 1.9.11. Tested on Android 7.1", "comment": { "comments": [ { "id": "434641", "author": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "body": "Any progress on this issue? \r\n\r\nWe are currently experiencing issues with URL-schemes. We currently have two apps. The first app opens the second app in order to request a token. The second app generates the token and gives this token back to the first app. \r\n\r\nThe setup is simple. I followed the instructions from Fokke (fokkezb.nl/2013/08/26/url-schemes-for-ios-and-android-1/) and it's working fine for iOS, I am able to open both apps and pass data, but on Android, we're dealing with an issue.\r\n\r\nWhen the second app is already open, the first app starts the second app another time, but in it's own app container. That's unwanted behaviour because I want to be navigated to the second app instead of opening a new instance. In some other cases, tapping \"back\" in the second app makes me go back to the splash screen etc..\r\n\r\nWe tried playing around with `android:launchMode=\"singleTask\"` and `singleInstance` but it didn't work as expected. \r\n\r\nIs it possible to take a look at this functionality?\r\n", "updateAuthor": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "created": "2018-02-20T09:09:44.000+0000", "updated": "2018-02-20T09:09:59.000+0000" }, { "id": "434686", "author": { "name": "zettageek", "key": "zettageek", "displayName": "Josh Lambert", "active": true, "timeZone": "America/Chicago" }, "body": "Bump. I need this also in two different projects. Happy to help anyway I can.", "updateAuthor": { "name": "zettageek", "key": "zettageek", "displayName": "Josh Lambert", "active": true, "timeZone": "America/Chicago" }, "created": "2018-02-21T02:18:11.000+0000", "updated": "2018-02-21T02:18:11.000+0000" }, { "id": "435440", "author": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~jvos] [~zettageek] Have you tried defining the property:\r\n\r\n{code:xml}\r\ntrue\r\n{code}\r\n\r\nIn your tiapp.xml?", "updateAuthor": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-03-09T22:23:55.000+0000", "updated": "2018-03-09T22:24:42.000+0000" }, { "id": "435480", "author": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "updateAuthor": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "created": "2018-03-12T13:41:26.000+0000", "updated": "2018-03-12T13:45:37.000+0000" }, { "id": "435552", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Right. Setting the \"intent-filter-new-task\" to true means it'll create a new task instance. This is also Android's default behavior.\r\n\r\nWe don't currently support launchMode \"singleTask\", but even if we did, the consequence of this setting is that it'll tear down all of the top most windows (aka: Android activities) you've created and display the root window. In our case, the splash screen window. Unfortunately, this is also by Google's design. There is no launchMode setting that 100% replicates iOS' behavior.", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-03-13T18:46:37.000+0000", "updated": "2018-03-13T19:57:58.000+0000" }, { "id": "435554", "author": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "body": "Today, thanks to a reply in TiSlack, I was looking for an alternative using intents.\r\n\r\nI tried following workaround:\r\n\r\n*+App A+*\r\n{code}\r\n var intent = Ti.Android.createIntent({\r\n className: com.example.appb.AppBActivity,\r\n packageName: com.exaple.appb,\r\n type: 'text/plain',\r\n action: Ti.Android.ACTION_MAIN\r\n });\r\n\r\n intent.addFlags(Ti.Android.FLAG_ACTIVITY_CLEAR_TOP);\r\n intent.addFlags(Ti.Android.FLAG_ACTIVITY_NEW_TASK);\r\n\r\n intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);\r\n\r\n intent.putExtra(\"URL\", url);\r\n\r\n Ti.Android.currentActivity.startActivity(intent);\r\n{code}\r\n\r\n*+App B+*\r\n{code}\r\n var intent = Ti.Android.createIntent({\r\n className: com.example.appa.AppAActivity,\r\n packageName: com.exaple.appa,\r\n type: 'text/plain',\r\n action: Ti.Android.ACTION_MAIN\r\n });\r\n\r\n intent.addFlags(Ti.Android.FLAG_ACTIVITY_CLEAR_TOP);\r\n intent.addFlags(Ti.Android.FLAG_ACTIVITY_NEW_TASK);\r\n\r\n intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);\r\n\r\n intent.putExtra(\"URL\", url);\r\n\r\n Ti.Android.currentActivity.startActivity(intent);\r\n{code}\r\n\r\nThis in both app's Alloy.js:\r\n{code}\r\n Ti.Android.currentActivity.onResume = function() {\r\n console.error(Ti.Android.currentActivity.intent.getStringExtra(\"URL\"));\r\n };\r\n{code}\r\n\r\nUsing these intents, I'm able to open App B from App A. Both apps have a button to switch to the other app. (Example setup)\r\n\r\nUnfortunately, following flow results in strange behaviour:\r\n1. App A opens App B, I can see URL in the console.error-logging\r\n2. App B opens App A, I can see URL in the console.error-logging\r\n3. Navigate to another activity in App A (for example, Activity 2), close the original first activity\r\n4. Close Activity 2, open Activity 1\r\n4. App A Activity 1 (same as in step 1) opens App B, I can see URL in the console.error-logging\r\n5. App B opens App A, but no console logging visible\r\n\r\nI see that the Ti.Android.currentActivity.onResume is added on TiRootActivity:\r\n\r\nTiRootActivity: (main) [0,0] checkpoint, on root activity resume\r\n[ERROR] null\r\n\r\nFor me, I tried a lot of other solutions: addEventListener on different events (newintent, onIntent), getActivity on the current window... I even tried startActivityForResult and I see that the callback is invoked directly, even when the second app isn't fully opened yet...", "updateAuthor": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "created": "2018-03-13T19:09:57.000+0000", "updated": "2018-03-13T20:53:59.000+0000" }, { "id": "435801", "author": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "body": "Please any update or workaround?", "updateAuthor": { "name": "jvos", "key": "jvos", "displayName": "Joren Vos", "active": true, "timeZone": "Europe/Brussels" }, "created": "2018-03-21T13:11:45.000+0000", "updated": "2018-03-21T13:11:45.000+0000" }, { "id": "435803", "author": { "name": "creative_jira_user", "key": "uzbbert", "displayName": "Creative", "active": false, "timeZone": "Europe/Amsterdam" }, "body": "You might get somewhere with hyperloop, but then again this suits native code better", "updateAuthor": { "name": "creative_jira_user", "key": "uzbbert", "displayName": "Creative", "active": false, "timeZone": "Europe/Amsterdam" }, "created": "2018-03-21T15:03:02.000+0000", "updated": "2018-03-21T15:03:02.000+0000" }, { "id": "437529", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Just to be clear here, there is no way to resume the Android app via an intent like how it works on iOS. Not in JavaScript. Not in Java code. If this is what you're after, then this is not an option.\r\n\r\nFrom a design standpoint, this is the downside of using Android activities for child windows. An intent is used to display a specific activity window and if you point it to the launcher activity (which is what you would normally do), then your only options in native code are:\r\n# Create a new UI task, which gives the appears of a new app instance. This is commonly done on Android. This is what our \"intent-filter-new-task\" tiapp.xml property enables.\r\n# Set up the intent to tear down the background UI task and create a new one via {{FLAG_ACTIVITY_CLEAR_TOP}}. This gives the appears that the app is restarting.\r\n\r\nThe launch mode \"singleTask\" (which you should *NOT* use in Titanium) is only a viable option when your Android app is NOT using activities for child windows. Because the consequence of this setting natively is that it tears down all child activities to display the root activity when resuming the background app. This won't match iOS' behave either. The \"singleTask\" option can only be rigged to work similar to iOS is if the app only uses 1 activity and displays child windows via fragments instead. This is not something Titanium supports because it would be a huge HUGE breaking change.\r\n\r\nI get the feeling that you're after iOS like behavior here. Unfortunately, it isn't possible. The 2 solutions you were using (\"intent-filter-new-task\" or \"FLAG_ACTIVITY_CLEAR_TOP\") are your only options.", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-05-09T19:03:10.000+0000", "updated": "2018-05-09T19:03:10.000+0000" }, { "id": "445207", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "This issue has been resolved in Titanium 8.0.0. Please see: [TIMOB-26075]", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-01-11T03:41:14.000+0000", "updated": "2019-01-11T03:41:14.000+0000" } ], "maxResults": 16, "total": 16, "startAt": 0 } } }