Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-25842] iOS: Cannot remove Ti.App.iOS.handleurl event-listener

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2018-05-22T15:53:50.000+0000
Affected Version/sRelease 6.3.0, Release 7.0.2
Fix Version/sRelease 7.3.0
ComponentsiOS
Labels6.3.0.GA, ios
ReporterDonald Anderson
AssigneeHans Knöchel
Created2018-03-06T13:23:30.000+0000
Updated2018-06-12T17:41:19.000+0000

Description

In my app Titanium.App.iOS.addEventListener("handleurl", iosHandleUrl) can successfully register an event listener for the handle url event. Titanium.App.iOS.addEventListener("handleurl", iosHandleUrl) fails to remove the event listener resulting in the iosHandleUrl function being called multiple times in my app, when redirected back to the app from the browser. To reproduce this I've create a sample project with the following code in index.js
function iosHandleUrl(e) {
	console.log("redirected to app from URL");
}

Ti.App.iOS.addEventListener("handleurl",iosHandleUrl);
Ti.App.iOS.removeEventListener("handleurl",iosHandleUrl);
Ti.App.iOS.addEventListener("handleurl",iosHandleUrl);
Ti.App.iOS.removeEventListener("handleurl",iosHandleUrl);
Ti.App.iOS.addEventListener("handleurl",iosHandleUrl);

Ti.UI.createWindow({
   backgroundColor: '#fff'
}).open();
And added the following to the plist in tiapp.xml.
<key>CFBundleURLTypes</key>
<array>
	<dict>
		<key>CFBundleURLName</key>
		<string>com.ideagen.handleurltest</string>
		<key>CFBundleURLSchemes</key>
		<array>
			<string>handleurltest</string>
		</array>
	</dict>
</array>
When I launch the app then open a browser and open handleurltest:// the expected behaviour is that "redirected to app from URL" should be logged once but the actual behaviour is that it's logged three times. The app was built against version 6.3.0.GA of the SDK.

Comments

  1. Hans Knöchel 2018-03-06

    This is a valid bug, lets fix this!
  2. Hans Knöchel 2018-03-06

    PR: https://github.com/appcelerator/titanium_mobile/pull/9910 Test-Case: See above
  3. Hans Knöchel 2018-03-07

    We need to re-think the app-module architecture, as this is also happening for all other Ti.App.iOS.* events (events that are not linked to an instance but a toplevel namespace), like shortcutitemclick. In my opinion, we should only fire one event per unique callback, so that
       Ti.App.iOS.addEventListener('handleurl', handleURL);
       Ti.App.iOS.removeEventListener('handleurl', handleURL);
       
       Ti.App.iOS.addEventListener('handleurl', handleURL);
       Ti.App.iOS.removeEventListener('handleurl', handleURL);
       
       Ti.App.iOS.addEventListener('handleurl', handleURL);
       Ti.App.iOS.addEventListener('handleurl', handleURL);
       
    Would still only trigger once, because the event listener is already added to the "handleURL" method. Is that thought correct? [~donald.anderson] Feedback welcome! If thats the case, I have a fix ready - notification, localnotificationaction and remotenotificationaction do it the same way btw. Full test:
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       function handleURL(e) {
         Ti.API.info('Event 1 triggered!');
       }
       
       function handleURL2(e) {
         Ti.API.info('Event 2 triggered!');
       }
       
       Ti.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger
       Ti.App.iOS.removeEventListener('handleurl', handleURL); // Removed - will NOT trigger anymore
       Ti.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger
       Ti.App.iOS.removeEventListener('handleurl', handleURL); // Removed - will NOT trigger anymore
       Ti.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger
       Ti.App.iOS.addEventListener('handleurl', handleURL2); // Added - will trigger
       
       win.open();
       
  4. Donald Anderson 2018-03-08

    I am using the handleurl event as part of a login flow. I had an issue with repeated logins if the user had navigated away from the login window at any point. I'm debouncing the event listener as a workaround. It sounds like the fix described above would fix my issue. As an aside though, after looking at the test cases in the previous comment i'm a bit uncertain about expected behaviour around around events when a listener is added more that once. For example If I add the following to my test app
       function orientationchange(){
       	console.log("orientationchange");
       }
       Ti.Gesture.addEventListener('orientationchange', orientationchange);
       Ti.Gesture.removeEventListener('orientationchange', orientationchange);
       Ti.Gesture.addEventListener('orientationchange', orientationchange);
       Ti.Gesture.removeEventListener('orientationchange', orientationchange);
       Ti.Gesture.addEventListener('orientationchange', orientationchange);
       Ti.Gesture.addEventListener('orientationchange', orientationchange);
       
    "orientationchange" is only logged once each time the device changes orientation. But if I add
       Ti.App.addEventListener('genericEvent', genericEvent);
       Ti.App.removeEventListener('genericEvent', genericEvent);
       Ti.App.addEventListener('genericEvent', genericEvent);
       Ti.App.removeEventListener('genericEvent', genericEvent);
       Ti.App.addEventListener('genericEvent', genericEvent);
       Ti.App.addEventListener('genericEvent', genericEvent);
       
       Ti.App.fireEvent('genericEvent');
       
    then "genericEvent" is logged twice when the app is opened. If a function is repeatedly registered as a listener to an event, when the event fires should the function be run once only or multiple times or does it depend on the event type?
  5. Samir Mohammed 2018-05-22

    FR Passed, Waiting on Jenkins build to merge.
  6. Samir Mohammed 2018-06-12

    Closing ticket. Fix can be seen in SDK Version: 7.3.0.v20180607210411 Test and other information can be found at: https://github.com/appcelerator/titanium_mobile/pull/9910

JSON Source