{ "id": "171248", "key": "TIMOB-25842", "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": [ { "id": "20115", "name": "Release 7.3.0", "archived": false, "released": true, "releaseDate": "2018-08-17" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2018-05-22T15:53:50.000+0000", "created": "2018-03-06T13:23:30.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [ "6.3.0.GA", "ios" ], "versions": [ { "id": "19906", "description": "", "name": "Release 6.3.0", "archived": false, "released": true, "releaseDate": "2017-11-01" }, { "id": "20060", "description": "", "name": "Release 7.0.2", "archived": false, "released": true, "releaseDate": "2018-02-09" } ], "issuelinks": [], "assignee": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2018-06-12T17:41:19.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": "10206", "name": "iOS", "description": "iOS Platform" } ], "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.\r\n\r\nTo reproduce this I've create a sample project with the following code in index.js\r\n\r\n{code}\r\nfunction iosHandleUrl(e) {\r\n\tconsole.log(\"redirected to app from URL\");\r\n}\r\n\r\nTi.App.iOS.addEventListener(\"handleurl\",iosHandleUrl);\r\nTi.App.iOS.removeEventListener(\"handleurl\",iosHandleUrl);\r\nTi.App.iOS.addEventListener(\"handleurl\",iosHandleUrl);\r\nTi.App.iOS.removeEventListener(\"handleurl\",iosHandleUrl);\r\nTi.App.iOS.addEventListener(\"handleurl\",iosHandleUrl);\r\n\r\nTi.UI.createWindow({\r\n backgroundColor: '#fff'\r\n}).open();\r\n{code}\r\n\r\nAnd added the following to the plist in tiapp.xml.\r\n{code}\r\nCFBundleURLTypes\r\n\r\n\t\r\n\t\tCFBundleURLName\r\n\t\tcom.ideagen.handleurltest\r\n\t\tCFBundleURLSchemes\r\n\t\t\r\n\t\t\thandleurltest\r\n\t\t\r\n\t\r\n\r\n{code}\r\nWhen 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.\r\n\r\nThe app was built against version 6.3.0.GA of the SDK.", "attachment": [], "flagged": false, "summary": "iOS: Cannot remove Ti.App.iOS.handleurl event-listener", "creator": { "name": "donald.anderson", "key": "donald.anderson", "displayName": "Donald Anderson", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "donald.anderson", "key": "donald.anderson", "displayName": "Donald Anderson", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "435243", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "This is a valid bug, lets fix this!", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-03-06T14:59:55.000+0000", "updated": "2018-03-06T14:59:55.000+0000" }, { "id": "435244", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "PR: https://github.com/appcelerator/titanium_mobile/pull/9910\r\n\r\nTest-Case: See above", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-03-06T15:02:41.000+0000", "updated": "2018-03-06T15:02:41.000+0000" }, { "id": "435301", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "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\r\n{code:js}\r\nTi.App.iOS.addEventListener('handleurl', handleURL);\r\nTi.App.iOS.removeEventListener('handleurl', handleURL);\r\n\r\nTi.App.iOS.addEventListener('handleurl', handleURL);\r\nTi.App.iOS.removeEventListener('handleurl', handleURL);\r\n\r\nTi.App.iOS.addEventListener('handleurl', handleURL);\r\nTi.App.iOS.addEventListener('handleurl', handleURL);\r\n{code}\r\nWould 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:\r\n{code:js}\r\nvar win = Ti.UI.createWindow({\r\n backgroundColor: '#fff'\r\n});\r\n\r\nfunction handleURL(e) {\r\n Ti.API.info('Event 1 triggered!');\r\n}\r\n\r\nfunction handleURL2(e) {\r\n Ti.API.info('Event 2 triggered!');\r\n}\r\n\r\nTi.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger\r\nTi.App.iOS.removeEventListener('handleurl', handleURL); // Removed - will NOT trigger anymore\r\nTi.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger\r\nTi.App.iOS.removeEventListener('handleurl', handleURL); // Removed - will NOT trigger anymore\r\nTi.App.iOS.addEventListener('handleurl', handleURL); // Added - will trigger\r\nTi.App.iOS.addEventListener('handleurl', handleURL2); // Added - will trigger\r\n\r\nwin.open();\r\n{code}", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-03-07T17:01:56.000+0000", "updated": "2018-03-07T17:06:17.000+0000" }, { "id": "435394", "author": { "name": "donald.anderson", "key": "donald.anderson", "displayName": "Donald Anderson", "active": true, "timeZone": "America/Los_Angeles" }, "body": "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.\r\n\r\nAs 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.\r\n\r\nFor example If I add the following to my test app\r\n{code}\r\nfunction orientationchange(){\r\n\tconsole.log(\"orientationchange\");\r\n}\r\nTi.Gesture.addEventListener('orientationchange', orientationchange);\r\nTi.Gesture.removeEventListener('orientationchange', orientationchange);\r\nTi.Gesture.addEventListener('orientationchange', orientationchange);\r\nTi.Gesture.removeEventListener('orientationchange', orientationchange);\r\nTi.Gesture.addEventListener('orientationchange', orientationchange);\r\nTi.Gesture.addEventListener('orientationchange', orientationchange);\r\n{code}\r\n\"orientationchange\" is only logged once each time the device changes orientation. But if I add\r\n{code}\r\nTi.App.addEventListener('genericEvent', genericEvent);\r\nTi.App.removeEventListener('genericEvent', genericEvent);\r\nTi.App.addEventListener('genericEvent', genericEvent);\r\nTi.App.removeEventListener('genericEvent', genericEvent);\r\nTi.App.addEventListener('genericEvent', genericEvent);\r\nTi.App.addEventListener('genericEvent', genericEvent);\r\n\r\nTi.App.fireEvent('genericEvent');\r\n{code}\r\nthen \"genericEvent\" is logged twice when the app is opened.\r\n\r\nIf 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?", "updateAuthor": { "name": "donald.anderson", "key": "donald.anderson", "displayName": "Donald Anderson", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-03-08T17:05:32.000+0000", "updated": "2018-03-08T17:05:41.000+0000" }, { "id": "437844", "author": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "body": "FR Passed, Waiting on Jenkins build to merge.", "updateAuthor": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-05-22T15:37:28.000+0000", "updated": "2018-05-22T15:37:28.000+0000" }, { "id": "438357", "author": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Closing ticket. Fix can be seen in SDK Version: 7.3.0.v20180607210411\r\n\r\nTest and other information can be found at: \r\nhttps://github.com/appcelerator/titanium_mobile/pull/9910", "updateAuthor": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-06-12T17:41:09.000+0000", "updated": "2018-06-12T17:41:09.000+0000" } ], "maxResults": 6, "total": 6, "startAt": 0 } } }