{ "id": "171307", "key": "TIMOB-25862", "fields": { "issuetype": { "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "name": "Improvement", "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": "20238", "description": "", "name": "Release 7.5.0", "archived": false, "released": true, "releaseDate": "2018-11-15" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2018-09-25T19:47:31.000+0000", "created": "2018-03-13T14:46:56.000+0000", "priority": { "name": "None", "id": "6" }, "labels": [ "parity" ], "versions": [ { "id": "20060", "description": "", "name": "Release 7.0.2", "archived": false, "released": true, "releaseDate": "2018-02-09" } ], "issuelinks": [ { "id": "56374", "type": { "id": "10001", "name": "Cloners", "inward": "is cloned into", "outward": "is cloned from" }, "outwardIssue": { "id": "171129", "key": "TIMOB-25786", "fields": { "summary": "Android: WebView eval JS timeout error ", "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": "None", "id": "6" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "56789", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "171644", "key": "TIMOB-26030", "fields": { "summary": "Android: TCP read() and write() methods cause a crash when running on main UI thread", "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": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "56866", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "172347", "key": "TIMOB-26411", "fields": { "summary": "API: Support async variants of Ti.IOStream methods", "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": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "updated": "2018-10-17T14:07:30.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" }, { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "h5. Issue\r\nEvaluating Javascript within a Webview is inherently a (possibly) long-running task. On Windows we evalJS accepts a second argument which is a callback function to receive the result (when it's ready). We should support this async variant of the Ti.UI.WebView.evalJS method on Android and iOS (especially now that there's an async method to do exactly this natively in Android as of apilevel-19).\r\n\r\n{code:javascript}\r\n// Existing sync call example\r\n// Result is returned sync\r\nvar result = webview.evalJS('1 + 3');\r\n\r\n// Async variant\r\n// this variant doesn't return a a value (basically it returns null or undefined but callers shouldn't use the result)\r\n// It fires off a thread/whatever to eval the JS and call the callback async.\r\nwebview.evalJS('1 + 3', function (result) {\r\n // do something with result\r\n});\r\n{code}\r\n", "attachment": [], "flagged": false, "summary": "Parity: Support async Ti.UI.Webview.evalJS call on Android & iOS", "creator": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "subtasks": [], "reporter": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "environment": null, "comment": { "comments": [ { "id": "435545", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "The big issue on iOS is that the UIWebView currently used in Ti.UI.WebView does not offer an API to both do the evalJS call async AND receive back a value. It can either be blocked on the main thread (sync) and return a value or do it async but do not return a value. Different to that, the \"more modern\" WKWebView that slowly replaces Ti.UI.WebView does it different and offers the API asynchronous by default. I've made [a module|https://github.com/appcelerator-modules/Ti.WKWebView] for that one a while ago, so devs can use it already. [~cwilliams] Let me know your thoughts!", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-03-13T17:46:34.000+0000", "updated": "2018-03-13T17:46:34.000+0000" }, { "id": "435553", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Here's an idea...\r\n\r\nHow about we create an async evalJS() equivalent which does *+not+* support returning a value. It merely executes the given script within the WebView. Developers already have a means to communicate back within the HTML via {{Ti.App.fireEvent()}}. They can use that to async communicate with the Titanium JavaScript.\r\nSometimes keeping it simple is better.", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-03-13T18:51:23.000+0000", "updated": "2018-03-13T18:51:23.000+0000" }, { "id": "435578", "author": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "body": "I think because I didn't add the example API we may be getting confused here.\r\n\r\nAn async variant of the method would not return a valid result. It should return null/undefined. Instead it schedules the eval to be run in the Webview and invokes the callback with the result when it's done.\r\n\r\nRight now the Android version I set up calls the callback function with the result, but doesn't really have a way to handle errors. We could consider a better version which would be more node-like so the first arg is an optional error object, the second argument is the result.\r\n{code:javascript}\r\nwebview.evalJS('1 + 3', function (err, result) {\r\n // err may be an Error object or string if there was an issue evaluating the JS.\r\n // if not, result should be a string\r\n});\r\n{code}\r\n\r\nI don't see why iOS wouldn't be able to do this. This is not some magical time-traveling variant that runs async but also returns a value sync.", "updateAuthor": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "created": "2018-03-14T14:32:10.000+0000", "updated": "2018-03-14T14:32:10.000+0000" }, { "id": "435601", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hold on. We can already do async eval on all platforms today.\r\n\r\nWe support {{Ti.App.addEventListener()}} and {{Ti.App.fireEvent()}} on the HTML side. So, developera already have the ability to do async event driven communication between the WebView's JavaScript and Titanium's JavaScript. And they can do an evalJS() equivalent by passing the JavaScript string via an event to the WebView like the below...\r\n\r\n{code:javascript}\r\nvar htmlText =\r\n\t\t'' +\r\n\t\t'' +\r\n\t\t'\t' +\r\n\t\t'\t\t

HTML Fire Event Test

' +\r\n\t\t'\t\t

' +\r\n\t\t'\t' +\r\n\t\t'\t' +\r\n\t\t'';\r\n\r\nvar window = Ti.UI.createWindow();\r\nvar webView = Ti.UI.createWebView({\r\n\thtml: htmlText,\r\n});\r\nwindow.add(webView);\r\nwindow.open();\r\n\r\nvar count = 1;\r\nsetInterval(function(e) {\r\n\tTi.App.fireEvent('app:webViewEval', {\r\n\t\tjavaScriptString: 'document.getElementById(\"label\").innerHTML = \"Counter: ' + count + '\"',\r\n\t});\r\n\tcount++;\r\n}, 1000);\r\n{code}\r\n\r\nThe above works on both Android and iOS.\r\n\r\n_*Edit:* The above mentioned solution will only work for HTML under the developer's control. It won't work with random webpages loaded from the Internet since they won't have any Titanium event listeners coded into the HTML's JavaScript. So, Chris' async evalJS() still has merit._", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-03-14T18:44:13.000+0000", "updated": "2018-03-14T19:41:23.000+0000" }, { "id": "441858", "author": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "body": "https://github.com/appcelerator/titanium_mobile/pull/9889\r\n\r\nAlso needs a thumb-up from either [~gmathews] or [~jquick]", "updateAuthor": { "name": "cwilliams", "key": "cwilliams", "displayName": "Christopher Williams", "active": true, "timeZone": "America/New_York" }, "created": "2018-09-20T18:26:21.000+0000", "updated": "2018-09-20T18:26:21.000+0000" }, { "id": "442694", "author": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "body": "*Closing ticket* Verified improvement in SDK Version {{7.5.0.v20181016071050}} using elements from the example in the description. \r\n\r\n*Test environment*\r\n{code:java}\r\nAPPC Studio: 5.1.0.201808080937\r\niPhone 6 Sim (iOS 12)\r\nAPPC CLI: 7.0.6\r\nOperating System Name: Mac OS Mojave\r\nOperating System Version: 10.14\r\nNode.js Version: 8.9.1\r\nXcode 10.0\r\n{code}\r\n", "updateAuthor": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-10-17T14:07:21.000+0000", "updated": "2018-10-17T14:07:21.000+0000" } ], "maxResults": 6, "total": 6, "startAt": 0 } } }