Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-28078] iOS14: Expose new APIs Titanium.Network.HTTPClient which will require while accessing local http server

GitHub Issuen/a
TypeNew Feature
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2020-09-11T19:54:03.000+0000
Affected Version/sn/a
Fix Version/sRelease 9.2.0
ComponentsiOS
Labelshttpclient, ios
ReporterVijay Singh
AssigneeVijay Singh
Created2020-08-11T19:53:47.000+0000
Updated2020-09-11T19:54:03.000+0000

Description

In iOS 14, Due to local network access prompt it may be that request get failed while waiting for user's permission. See more detail in WWDC video https://developer.apple.com/videos/play/wwdc2020/10110/. In titanium, we need to provide APIs corresponding to [waitsForConnectivity](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity) and [timeoutIntervalForResource ](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1408153-timeoutintervalforresource)

Comments

  1. Joshua Quick 2020-08-11

    [~vijaysingh], this ticket states iOS14 will prompt the end-user when you attempt to connect to an end-point on the LAN. Does this also include "localhost"? _(I would assume so.)_ The below test code uses HTTPClient to send a request to a local TCP socket. We should test this on on iOS14 to see what the behavior is.
       var listenSocket = Ti.Network.Socket.createTCP({
       	host: "localhost",
       	port: 40404,
       	accepted: function(e) {
       		Ti.API.info("@@@ accepted() host: " + e.inbound.host);
       		Ti.Stream.pump(e.inbound, function(e) {
       			var httpRequestMessage = "";
       			if (e.buffer) {
       				httpRequestMessage = e.buffer.toString();
       			}
       			Ti.API.info("@@@ Received HTTP Request:\n" + httpRequestMessage);
       			listenSocket.accept({ timeout: 30000 });
       		}, 1024, true);
       	},
       	error: function(e) {
       		Ti.API.info("@@@ Socket Listener Error: " + e.error);
       	},
       });
       listenSocket.listen();
       listenSocket.accept({ timeout: 30000 });
       
       var window = Titanium.UI.createWindow();
       var buttonView = Ti.UI.createButton({ title: "Send HTTP Request" });
       buttonView.addEventListener("click", function(e) {
       	var url = "http://localhost:40404?test=hello+world";
       	Ti.API.info("@@@ Sending HTTP request for url:\n" + url);
       	var httpClient = Ti.Network.createHTTPClient();
       	httpClient.open("POST", url);
       	httpClient.send("This is the HTTP content.");
       });
       window.add(buttonView);
       window.open();
       
  2. Joshua Quick 2020-08-11

    We should also double-check LiveView on iOS14 since it operates over the LAN. [~eharris], this is a heads-up. You "might" get sucked into this.
  3. Vijay Singh 2020-08-11

    [~jquick] Thanks for test case. It is not showing prompt if host is "localhost". If we set the host to the address of the wifi interface (Ti.Platform.address), it shows the prompt. Updated Test Case -
       var hostname = Ti.Platform.address;
       
       var listenSocket = Ti.Network.Socket.createTCP({
       	host: hostname,
       	port: 40404,
       	accepted: function(e) {
       		Ti.API.info("@@@ accepted() host: " + e.inbound.host);
       		Ti.Stream.pump(e.inbound, function(e) {
       			var httpRequestMessage = "";
       			if (e.buffer) {
       				httpRequestMessage = e.buffer.toString();
       			}
       			Ti.API.info("@@@ Received HTTP Request:\n" + httpRequestMessage);
       			listenSocket.accept({ timeout: 30000 });
       		}, 1024, true);
       	},
       	error: function(e) {
       		Ti.API.info("@@@ Socket Listener Error: " + e.error);
       	},
       });
       listenSocket.listen();
       listenSocket.accept({ timeout: 30000 });
        
       var window = Titanium.UI.createWindow();
       var buttonView = Ti.UI.createButton({ title: "Send HTTP Request" });
       buttonView.addEventListener("click", function(e) {
       	var url = "http://" + hostname + ":40404?test=hello+world";
       	Ti.API.info("@@@ Sending HTTP request for url:\n" + url);
       	var httpClient = Ti.Network.createHTTPClient();
       	httpClient.open("POST", url);
       	httpClient.send("This is the HTTP content.");
       });
       window.add(buttonView);
       window.open();
       
  4. Vijay Singh 2020-08-12

    PR(APSHttpClient)- https://github.com/appcelerator/APSHTTPClient/pull/53 PR (SDK) - https://github.com/appcelerator/titanium_mobile/pull/11897
  5. Vijay Singh 2020-08-12

    Test Case 1. 1. Run app on iOS 14 device. 2. Go to iPhone settings and disconnect from wifi. 3. Open app and click on 'Send HTTP request'. It should not show error. 4. Again go to settings and connect wifi, it should show 'request successful' 5. In test case uncomment line having "timeoutForResource: 10000". 6. Run app again. 7. Disconnect wifi. 8. Click on 'Send HTTP Request', 9. Wait for 10 seconds, it should show 'request failed'
       var window = Titanium.UI.createWindow();
       var buttonView = Ti.UI.createButton({ title: "Send HTTP Request" });
       buttonView.addEventListener("click", function(e) {
       	var url = "https://www.google.com";
       	var httpClient = Ti.Network.createHTTPClient({
       		waitsForConnectivity: true,
       	//	timeoutForResource:  10000
       	});
       	httpClient.open("GET", url);
       	httpClient.send();
       	httpClient.onload =  function() {
       		alert('request successful');
       	}
       
       	httpClient.onerror =  function(e) {
       		alert('request failed');
                      Ti.API.info("@@@ Error is: ");
       		Ti.API.error(JSON.stringify(e));
       	}
       });
       window.add(buttonView);
       window.open();
       
  6. Vijay Singh 2020-08-13

    Test Case 2: 1. Create an app, add test case and run on iOS 14 device. 2. Click on 'Send HTTP Request' . 3. An alert should show with some default message. See the log. There should be no error message. 4. Click on 'Ok'. See the log. There should be message having 'Received HTTP Request'. 5. Delete the app from iPhone. 6. Set the 'waitsForConnectivity' to false in code and run app again. 7. Click on 'Send HTTP Request', alert should be shown. 8. Without doing any action on alert see the log. It should show error message. 9. Delete app from iPhone. Add key 'NSLocalNetworkUsageDescription' in tiapp.xml (see doc). 10. Run again. On click of 'Send HTTP Request' alert should be shown with message given in value of key 'NSLocalNetworkUsageDescription'
       var hostname = Ti.Platform.address;
        
       var listenSocket = Ti.Network.Socket.createTCP({
       	host: hostname,
       	port: 40404,
       	accepted: function(e) {
       		Ti.API.info("@@@ accepted() host: " + e.inbound.host);
       		Ti.Stream.pump(e.inbound, function(e) {
       			var httpRequestMessage = "";
       			if (e.buffer) {
       				httpRequestMessage = e.buffer.toString();
       			}
       			Ti.API.info("@@@ Received HTTP Request:\n" + httpRequestMessage);
       			listenSocket.accept({ timeout: 30000 });
       		}, 1024, true);
       	},
       	error: function(e) {
       		Ti.API.info("@@@ Socket Listener Error: " + e.error);
       	},
       });
       listenSocket.listen();
       listenSocket.accept({ timeout: 30000 });
        
       var window = Titanium.UI.createWindow();
       var buttonView = Ti.UI.createButton({ title: "Send HTTP Request" });
       buttonView.addEventListener("click", function(e) {
       	var url = "http://" + hostname + ":40404?test=hello+world";
       	Ti.API.info("@@@ Sending HTTP request for url:\n" + url);
       	var httpClient = Ti.Network.createHTTPClient({
       		waitsForConnectivity: true,
       	});
       	httpClient.open("POST", url);
       	httpClient.send("This is the HTTP content.");
       	httpClient.onload =  function() {
       		alert('request successful');
       	}
       
       	httpClient.onerror =  function(e) {
       		Ti.API.info("@@@ Error is: ");
       		Ti.API.error(JSON.stringify(e));
       	}
       });
       window.add(buttonView);
       window.open();
       
  7. Ewan Harris 2020-08-18

    [~jquick], thanks for the heads up, LiveView injects the development machines IP (so something like 192.168.x.y), I don't currently have an iOS 14 device and can't even do LiveView to device on my Axway MBP as something is blocking the port from being accessed. I watched the video and it seems like we'll have to update LiveView for this, have you been able to test it at all [~vijaysingh]? This totally could be a pain to handle I feel if we need to somehow inject a plist value to describe _why_ that prompt is occuring
  8. Vijay Singh 2020-08-19

    [~eharris] I didn't test it for LiveView. Let me try. To note here - If we do not add key in plist, it will show the prompt. But message will be generic. To show more relevant message, it need to be added.
  9. Vijay Singh 2020-08-20

  10. Satyam Sekhri 2020-08-28

    FR Passed. Waiting for Jenkins build
  11. Satyam Sekhri 2020-09-11

    Verified on: Mac OS: 10.15.4 SDK: 9.2.0.v20200911073932, 9.3.0.v20200911052140 Appc CLI: 8.1.0 JDK: 11.0.4 Node: 10.17.0 Studio: 6.0.0.202005141803 Xcode: 12.0 Beta6 iPhone 7Plus(v14.0 Beta6)

JSON Source