Uploaded image for project: 'Apache Cordova'
  1. Apache Cordova
  2. CB-7991 WKWebView integration
  3. CB-7539

[WKWebView][iOS 8] Use local webserver option to load local HTML file from www

    Details

    • Type: Sub-task
    • Status: Resolved
    • Priority: Blocker
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: cordova-ios
    • Labels:
      None

      Description

      This workaround is because of this bug:
      http://www.openradar.me/radar?id=5839348817723392
      (filed with Apple of course also)

      I'm still hoping that Apple fixes this in iOS 8.1, but we should have this as a contingency plan.

      Create this as an included plugin, so it can be extracted later if need be.

      We need to secure access to the local webserver, probably through a session token in the header, since background apps can have access to the webserver. The session token is passed down to the initially loaded local page specified from the <content> tag in config.xml, and should be used in the cordova.exec call. We would also need to implement local proxy support , see CB-7348

      This all sounds more complex than it needs to be than just loading a file url – wishing Apple would just fix this in iOS 8.1 instead.

        Activity

        Hide
        shazron Shazron Abdullah added a comment -

        Read the README for the plugin, you have to use the 4.0.x branch.

        Show
        shazron Shazron Abdullah added a comment - Read the README for the plugin, you have to use the 4.0.x branch.
        Hide
        dotnetwise DotNetWise added a comment -

        Uhm, I'm targeting Cordova 3.7.0 (iOS version) and it seems I don't have Cordova/NSDictionary+CordovaPreferences.h

        Show
        dotnetwise DotNetWise added a comment - Uhm, I'm targeting Cordova 3.7.0 (iOS version) and it seems I don't have Cordova/NSDictionary+CordovaPreferences.h
        Hide
        dotnetwise DotNetWise added a comment -

        I have forked the repo, and only let the cordova-wkwebview-engine plugin https://github.com/dotnetwise/cordova-wkwebview-engine/ so I can test it without any other dependencies.

        Will keep you posted.

        Show
        dotnetwise DotNetWise added a comment - I have forked the repo, and only let the cordova-wkwebview-engine plugin https://github.com/dotnetwise/cordova-wkwebview-engine/ so I can test it without any other dependencies. Will keep you posted.
        Hide
        shazron Shazron Abdullah added a comment -

        Let's only discuss what is concrete and not apply theoreticals. If the localwebserver conflicts, which it won't (since it uses an unused port), then please report back, with an actual bug.

        Show
        shazron Shazron Abdullah added a comment - Let's only discuss what is concrete and not apply theoreticals. If the localwebserver conflicts, which it won't (since it uses an unused port), then please report back, with an actual bug.
        Hide
        dotnetwise DotNetWise added a comment - - edited

        Locally, I haven't got so far yet, but I think won't work - since meteor is using it's own mappings and starting the app via `http://meteor.local`
        I think this will clash with your own local server

        Since, from meteor we won't be on the file:/// protocol is there a way we can avoid the usage of the local server?

        Barely assume the app will itself redirect to a http://meteor.local which is not (and should not be) part of this plugin.

        Show
        dotnetwise DotNetWise added a comment - - edited Locally, I haven't got so far yet, but I think won't work - since meteor is using it's own mappings and starting the app via ` http://meteor.local ` I think this will clash with your own local server Since, from meteor we won't be on the file:/// protocol is there a way we can avoid the usage of the local server? Barely assume the app will itself redirect to a http://meteor.local which is not (and should not be) part of this plugin.
        Hide
        shazron Shazron Abdullah added a comment - - edited

        Ah, so then it's not about having a local web server solution, it's an install problem that you have. How are you adding the plugins? It is absolutely supported even within subfolders.

        cordova plugin add [git repo url]#branch:folder
        

        I even refer to this syntax in the plugin's README.md

        Show
        shazron Shazron Abdullah added a comment - - edited Ah, so then it's not about having a local web server solution, it's an install problem that you have. How are you adding the plugins? It is absolutely supported even within subfolders. cordova plugin add [git repo url]#branch:folder I even refer to this syntax in the plugin's README.md
        Hide
        dotnetwise DotNetWise added a comment - - edited

        org.apache.cordova.labs.wkwebviewengine@https://github.com/apache/cordova-plugins/tarball/1e1f519c374fb0dea44512c8782029eac8f37039

        When you add the plugin via git/tarball it expects to find the plugin.xml in the root, but since this repo is containing multiple plugins, it can't be even installed

        Show
        dotnetwise DotNetWise added a comment - - edited org.apache.cordova.labs.wkwebviewengine@ https://github.com/apache/cordova-plugins/tarball/1e1f519c374fb0dea44512c8782029eac8f37039 When you add the plugin via git/tarball it expects to find the plugin.xml in the root, but since this repo is containing multiple plugins, it can't be even installed
        Hide
        shazron Shazron Abdullah added a comment -

        Yes it is still needed. Apple hasn't fixed the problem.

        I have no idea why it breaks Meteor - that framework is not really my concern. If you have more info other than "it breaks Meteor", or send a pull request, perhaps we can help with fixing any integration issues with this particular framework.

        Show
        shazron Shazron Abdullah added a comment - Yes it is still needed. Apple hasn't fixed the problem. I have no idea why it breaks Meteor - that framework is not really my concern. If you have more info other than "it breaks Meteor", or send a pull request, perhaps we can help with fixing any integration issues with this particular framework.
        Hide
        dotnetwise DotNetWise added a comment -

        With IOS 8.2 is the local sever still being needed?
        It breaks Meteor, so would be great to drop it - is it possible?

        Show
        dotnetwise DotNetWise added a comment - With IOS 8.2 is the local sever still being needed? It breaks Meteor, so would be great to drop it - is it possible?
        Hide
        shazron Shazron Abdullah added a comment -

        See older comments about the local webserver plugin.

        Show
        shazron Shazron Abdullah added a comment - See older comments about the local webserver plugin.
        Hide
        dunielson Dustin Nielson added a comment -

        Here's the issue I opened: https://issues.apache.org/jira/browse/CB-8047. This is my first attempt at an issue so if I've done it incorrectly please let me know.

        Thanks.

        Show
        dunielson Dustin Nielson added a comment - Here's the issue I opened: https://issues.apache.org/jira/browse/CB-8047 . This is my first attempt at an issue so if I've done it incorrectly please let me know. Thanks.
        Hide
        shazron Shazron Abdullah added a comment -

        Seems like a bug in the `wkwebview` branch. Could you please file a new issue so it can be tracked?

        Show
        shazron Shazron Abdullah added a comment - Seems like a bug in the `wkwebview` branch. Could you please file a new issue so it can be tracked?
        Hide
        dunielson Dustin Nielson added a comment -

        Hi Shazron,

        Here's a link to my project. It's pretty much the vanilla implementation from your instructions with me manually adding the webkit framework and checking the boxes for the supported orientations.

        https://github.com/dunielson/kiosk

        Thanks.

        Show
        dunielson Dustin Nielson added a comment - Hi Shazron, Here's a link to my project. It's pretty much the vanilla implementation from your instructions with me manually adding the webkit framework and checking the boxes for the supported orientations. https://github.com/dunielson/kiosk Thanks.
        Hide
        shazron Shazron Abdullah added a comment -

        Hi Dustin,
        Thanks for the bug report. If you could post the example project so I can see? (on github, or a download link etc).

        Show
        shazron Shazron Abdullah added a comment - Hi Dustin, Thanks for the bug report. If you could post the example project so I can see? (on github, or a download link etc).
        Hide
        dunielson Dustin Nielson added a comment -

        I hope this is an appropriate place to make this comment if not my apologies. I've successfully managed to get the plugin working on my iphone 6, ipad mini 2, and my retina ipad using Shazron's instructions from the wkwebview plugin repository.

        I'm having an issue with the screen not rotating on all of these devices although my deployment info shows each orientation checked and my plist file shows each of the orientations. If this is something I'm doing incorrectly I would appreciate a pointer to get me headed in the right direction. If it's an actual issue then I just wanted to point it out.

        I'm looking forward to seeing this plugin move forward as I can see a real value in having a local web server available.

        Show
        dunielson Dustin Nielson added a comment - I hope this is an appropriate place to make this comment if not my apologies. I've successfully managed to get the plugin working on my iphone 6, ipad mini 2, and my retina ipad using Shazron's instructions from the wkwebview plugin repository. I'm having an issue with the screen not rotating on all of these devices although my deployment info shows each orientation checked and my plist file shows each of the orientations. If this is something I'm doing incorrectly I would appreciate a pointer to get me headed in the right direction. If it's an actual issue then I just wanted to point it out. I'm looking forward to seeing this plugin move forward as I can see a real value in having a local web server available.
        Hide
        shazron Shazron Abdullah added a comment -

        Added local-webserver plugin: https://github.com/apache/cordova-plugins/tree/master/local-webserver
        Nothing fancy – just to get a proof of concept right now to work with https://github.com/apache/cordova-plugins/tree/master/wkwebview-engine

        Show
        shazron Shazron Abdullah added a comment - Added local-webserver plugin: https://github.com/apache/cordova-plugins/tree/master/local-webserver Nothing fancy – just to get a proof of concept right now to work with https://github.com/apache/cordova-plugins/tree/master/wkwebview-engine
        Hide
        shazron Shazron Abdullah added a comment - - edited

        Nick, no that is a separate issue. See the actual radar bug referenced in the description of this issue, and my previous comment.

        Show
        shazron Shazron Abdullah added a comment - - edited Nick, no that is a separate issue. See the actual radar bug referenced in the description of this issue, and my previous comment.
        Hide
        nickpadilla Nick Padilla added a comment -

        According to http://www.openradar.me/18299758 this has been fixed as of 8.0.2; my ipad is already running this version. Is there a way i can run/test the WKWebView using Phonegap 3.6.3?

        Show
        nickpadilla Nick Padilla added a comment - According to http://www.openradar.me/18299758 this has been fixed as of 8.0.2; my ipad is already running this version. Is there a way i can run/test the WKWebView using Phonegap 3.6.3?
        Hide
        shazron Shazron Abdullah added a comment -

        Update, the file url loading bug is fixed! See: http://trac.webkit.org/changeset/174029/trunk
        It appears the bug was a result of their updated sandboxing.

        However, I tested it in iOS 8.1 beta and the new API function is not there yet sad-face. Hopefully it will be in 8.2 or 8.3. We should get the WKWebView train running again once that API function is in, assuming it works as advertised.

        Show
        shazron Shazron Abdullah added a comment - Update, the file url loading bug is fixed! See: http://trac.webkit.org/changeset/174029/trunk It appears the bug was a result of their updated sandboxing. However, I tested it in iOS 8.1 beta and the new API function is not there yet sad-face . Hopefully it will be in 8.2 or 8.3. We should get the WKWebView train running again once that API function is in, assuming it works as advertised.
        Hide
        dstaudigel Daniel Staudigel added a comment -

        You're right - there actually is no need to try this out in hopes that it's a simple error, I see a ton of stuff online about how different WKWebView is!

        Show
        dstaudigel Daniel Staudigel added a comment - You're right - there actually is no need to try this out in hopes that it's a simple error, I see a ton of stuff online about how different WKWebView is!
        Hide
        shazron Shazron Abdullah added a comment -

        Well I should know since I wrote it for Cordova (the NSURLProtocol stuff). Independently verify away - it's pretty clear that NSURLProtocol is not used in WKWebView, it is on a totally different system - requests are made out of process.

        Show
        shazron Shazron Abdullah added a comment - Well I should know since I wrote it for Cordova (the NSURLProtocol stuff). Independently verify away - it's pretty clear that NSURLProtocol is not used in WKWebView, it is on a totally different system - requests are made out of process.
        Hide
        dstaudigel Daniel Staudigel added a comment -

        I'm not exactly sure how to reproduce your tests, but I assume you did it for a variety of different protocols (file, http, cdv-proto, whatever). I remember having some trouble getting this mechanism to work in iOS many moons ago, even with UIWebView. If I have free time I'll see if I can independently verify your bug report with the code I have lying around.

        Show
        dstaudigel Daniel Staudigel added a comment - I'm not exactly sure how to reproduce your tests, but I assume you did it for a variety of different protocols (file, http, cdv-proto, whatever). I remember having some trouble getting this mechanism to work in iOS many moons ago, even with UIWebView. If I have free time I'll see if I can independently verify your bug report with the code I have lying around.
        Hide
        shazron Shazron Abdullah added a comment -

        Daniel, this won't work. WKWebView does not use NSURLProtocol at all. See: https://issues.apache.org/jira/browse/CB-7049

        Show
        shazron Shazron Abdullah added a comment - Daniel, this won't work. WKWebView does not use NSURLProtocol at all. See: https://issues.apache.org/jira/browse/CB-7049
        Hide
        dstaudigel Daniel Staudigel added a comment -

        Another way around this is to create a custom URI scheme by creating a subclass to NSProtocol. I have a bunch of code lying around that does this, both redirecting to online resources and using local files. If WKWebView doesn't support file:// properly, we may be able to just "fix" this functionality using this technique. Because we are loading our own NSProtocol after the built-in one is loaded, it will take precedence. Because it's a file:// URI, the CORS things should work properly. Further, backgrounded apps won't be able to get to it.

        Show
        dstaudigel Daniel Staudigel added a comment - Another way around this is to create a custom URI scheme by creating a subclass to NSProtocol. I have a bunch of code lying around that does this, both redirecting to online resources and using local files. If WKWebView doesn't support file:// properly, we may be able to just "fix" this functionality using this technique. Because we are loading our own NSProtocol after the built-in one is loaded, it will take precedence. Because it's a file:// URI, the CORS things should work properly. Further, backgrounded apps won't be able to get to it.
        Hide
        limingxie Liming Xie added a comment -

        Shazron, I like the proposal. It does make sense.

        Show
        limingxie Liming Xie added a comment - Shazron, I like the proposal. It does make sense.
        Hide
        shazron Shazron Abdullah added a comment - - edited

        Thanks Liming Xie, I like the idea. Here's what I'm thinking:

        To use WKWebView as the default web engine, we need a local http server running (at least until Apple fixes this bug). This will NOT be embedded as part of Cordova, but is a plugin with "onload" = true in the feature tag.

        This accomplishes two things:
        1. Maintenance of the plugin is out of Cordova committer's hands, we don't have to be experts
        2. Ability to swap (if need be) another http server. Not sure if this is that important

        However Cordova still needs to discover the http server during startup. This can be achieved through Preferences, and a new protocol these http servers will need to implement (simple stuff).

        I'm thinking:

        <preference name="CordovaHttpServer" value="CorHttpd" /> <!-- the http server plugin feature name -->
        

        CorHttpd will implement, say, CDVHttpServerProtocol My proposal:

        - (void) startServer:(NSURL*)root; // we want a randomized port
        - (void) stopServer;
        - (NSURL*) serverUrl; // return the server url
        - (void) setSessionKey:(NSString*)sessionKey; // not sure how this will work yet at all.
        

        If preference UseWKWebView is true:

        1. look for the CordovaHttpServer preference, now we know which plugin is the loaded http server.
        2. confirm http server plugin conforms to CDVHttpServerProtocol,
        3. call CDVHttpServerProtocol::startServer, passing in the www root (we need to pass in the exact html file to load)
        4. generate a UUID for the sessionKey, set the sessionKey through CDVHttpServerProtocol:setSessionKey,
        5. grab the serverUrl through CDVHttpServerProtocol::serverUrl
        6. pass the serverUrl to WKWebView

        If the CordovaHttpServer plugin is missing, we error out and prompt the user to install one, with a recommendation (in this case CorHttpd).

        Show
        shazron Shazron Abdullah added a comment - - edited Thanks Liming Xie, I like the idea. Here's what I'm thinking: To use WKWebView as the default web engine, we need a local http server running (at least until Apple fixes this bug). This will NOT be embedded as part of Cordova, but is a plugin with "onload" = true in the feature tag. This accomplishes two things: 1. Maintenance of the plugin is out of Cordova committer's hands, we don't have to be experts 2. Ability to swap (if need be) another http server. Not sure if this is that important However Cordova still needs to discover the http server during startup. This can be achieved through Preferences, and a new protocol these http servers will need to implement (simple stuff). I'm thinking: <preference name= "CordovaHttpServer" value= "CorHttpd" /> <!-- the http server plugin feature name --> CorHttpd will implement, say, CDVHttpServerProtocol My proposal: - (void) startServer:(NSURL*)root; // we want a randomized port - (void) stopServer; - (NSURL*) serverUrl; // return the server url - (void) setSessionKey:(NSString*)sessionKey; // not sure how this will work yet at all. If preference UseWKWebView is true: look for the CordovaHttpServer preference, now we know which plugin is the loaded http server. confirm http server plugin conforms to CDVHttpServerProtocol, call CDVHttpServerProtocol::startServer, passing in the www root (we need to pass in the exact html file to load) generate a UUID for the sessionKey, set the sessionKey through CDVHttpServerProtocol:setSessionKey, grab the serverUrl through CDVHttpServerProtocol::serverUrl pass the serverUrl to WKWebView If the CordovaHttpServer plugin is missing, we error out and prompt the user to install one, with a recommendation (in this case CorHttpd).
        Hide
        limingxie Liming Xie added a comment -

        I am for the proposal to embed a local web server into cordova. it will benefit a lot to HTML5 games.

        With the WebGL and WKWebView introduced in iOS8, and the Android L, HTML5 game performance is largely improved. The era for HTML5 on mobile phone is coming.

        The only bottleneck is the AJAX and domain issue. As resources are loaded via AJAX, canvas domain is also restricted for security reason. For example, the most popular phaser.js game engine, a httpd is always required. If this issue can be solved, it will largely change the HTML5 mobile game ecosystem.

        I've implemented a plugin to embed a tiny webserver into Cordova, CocoaHTTPServer (iOS) and NanoHTTPD (java) are used in the plugin. It's being used by Meteor.
        https://github.com/floatinghotpot/cordova-httpd

        There are quite a few app to have local httpd embeded. I guess the app review is not a blocking issue. On the other hand, the security control on remote access need be carefully designed of course.

        If needed, maybe I can contribute some effort to this feature.

        Show
        limingxie Liming Xie added a comment - I am for the proposal to embed a local web server into cordova. it will benefit a lot to HTML5 games. With the WebGL and WKWebView introduced in iOS8, and the Android L, HTML5 game performance is largely improved. The era for HTML5 on mobile phone is coming. The only bottleneck is the AJAX and domain issue. As resources are loaded via AJAX, canvas domain is also restricted for security reason. For example, the most popular phaser.js game engine, a httpd is always required. If this issue can be solved, it will largely change the HTML5 mobile game ecosystem. I've implemented a plugin to embed a tiny webserver into Cordova, CocoaHTTPServer (iOS) and NanoHTTPD (java) are used in the plugin. It's being used by Meteor. https://github.com/floatinghotpot/cordova-httpd There are quite a few app to have local httpd embeded. I guess the app review is not a blocking issue. On the other hand, the security control on remote access need be carefully designed of course. If needed, maybe I can contribute some effort to this feature.
        Hide
        csantana Carlos Santana added a comment -
        Show
        csantana Carlos Santana added a comment - SGTM Shazron Abdullah
        Hide
        shazron Shazron Abdullah added a comment -

        It's perfectly good code, they just didn't bother to update it for the later SDKs, because... not important to them.
        The only way to see if this passes app review is to submit for app review. I wouldn't stir the hornet's nest by filing a radar – lots of other apps use local webservers. GoodReader for example, and other apps that allow people to download the documents from the apps by sending ppl to a local url.

        Show
        shazron Shazron Abdullah added a comment - It's perfectly good code, they just didn't bother to update it for the later SDKs, because... not important to them. The only way to see if this passes app review is to submit for app review. I wouldn't stir the hornet's nest by filing a radar – lots of other apps use local webservers. GoodReader for example, and other apps that allow people to download the documents from the apps by sending ppl to a local url.
        Hide
        csantana Carlos Santana added a comment -

        even without blessing from Apple and getting feedback. For Apps that are not publish to the App store like Enterprise Apps I think it will be still useful to have this in.
        my 2 cents

        Show
        csantana Carlos Santana added a comment - even without blessing from Apple and getting feedback. For Apps that are not publish to the App store like Enterprise Apps I think it will be still useful to have this in. my 2 cents
        Hide
        csantana Carlos Santana added a comment -

        My point is that I saw this and means that Xcode is no longer recommending this code.

        and yes I agree with you using other code is even worst.

        Is there a way we can validate that if we use this code it passes App review. Maybe opening a radar asking?

        Show
        csantana Carlos Santana added a comment - My point is that I saw this and means that Xcode is no longer recommending this code. and yes I agree with you using other code is even worst. Is there a way we can validate that if we use this code it passes App review. Maybe opening a radar asking?
        Hide
        shazron Shazron Abdullah added a comment -

        If we update to whatever Xcode recommends, should be ok.

        We only need this as an asset loader. I'm reluctant to use other code with more whizbang features that we don't need and don't understand. Trying to keep it simple.

        Show
        shazron Shazron Abdullah added a comment - If we update to whatever Xcode recommends, should be ok. We only need this as an asset loader. I'm reluctant to use other code with more whizbang features that we don't need and don't understand. Trying to keep it simple.
        Hide
        csantana Carlos Santana added a comment -

        I went to the link and get this, any concerns?

        Retired Document

        Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.

        Show
        csantana Carlos Santana added a comment - I went to the link and get this, any concerns? Retired Document Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
        Hide
        shazron Shazron Abdullah added a comment -

        Use Apple licensed code: https://developer.apple.com/legacy/library/samplecode/CocoaHTTPServer/Listings/CocoaHTTPServer_m.html
        (we already use Reachability, and acknowledge Apple's code – so this would be be easiest).

        More full featured (based off the Apple code above), but I don't think we need any of the new features:
        https://github.com/robbiehanson/CocoaHTTPServer

        Show
        shazron Shazron Abdullah added a comment - Use Apple licensed code: https://developer.apple.com/legacy/library/samplecode/CocoaHTTPServer/Listings/CocoaHTTPServer_m.html (we already use Reachability, and acknowledge Apple's code – so this would be be easiest). More full featured (based off the Apple code above), but I don't think we need any of the new features: https://github.com/robbiehanson/CocoaHTTPServer
        Hide
        shazron Shazron Abdullah added a comment -

        Note to people saying WKWebView::loadHTMLString can work... but no. You can load the initial HTML file, but any further local assets referenced in that file will not load.

        The evidence points to this being a bug, and not a policy change. See http://www.openradar.me/radar?id=5834555097350144 where xhr upload doesn't work, presumably because it can't load the selected local file.

        Show
        shazron Shazron Abdullah added a comment - Note to people saying WKWebView::loadHTMLString can work... but no. You can load the initial HTML file, but any further local assets referenced in that file will not load. The evidence points to this being a bug, and not a policy change. See http://www.openradar.me/radar?id=5834555097350144 where xhr upload doesn't work, presumably because it can't load the selected local file.
        Hide
        shazron Shazron Abdullah added a comment -

        I'm not so sure about the local proxy now and us automatically overwriting xhr, let's keep it simple. This will break apps that rely on cross-origin restrictions not to be on like in UIWebView, but their tests should detect this right away - going forward the servers they connect to should be CORS compliant and allow null origins.

        The local webserver should do one thing, and one thing only – serve local assets from the local www folder, that's it.

        The local proxy can be a plugin that 3rd parties implement, and the dev explicitly installs. I'm not sure we are the ones to implement it.

        Show
        shazron Shazron Abdullah added a comment - I'm not so sure about the local proxy now and us automatically overwriting xhr, let's keep it simple. This will break apps that rely on cross-origin restrictions not to be on like in UIWebView, but their tests should detect this right away - going forward the servers they connect to should be CORS compliant and allow null origins. The local webserver should do one thing, and one thing only – serve local assets from the local www folder, that's it. The local proxy can be a plugin that 3rd parties implement, and the dev explicitly installs. I'm not sure we are the ones to implement it.

          People

          • Assignee:
            shazron Shazron Abdullah
            Reporter:
            shazron Shazron Abdullah
          • Votes:
            6 Vote for this issue
            Watchers:
            18 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development