Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support WKWebView and Cordova iOS version 4.0.0 #685

Closed
BozzaDaniel opened this issue Oct 22, 2015 · 44 comments
Closed

Support WKWebView and Cordova iOS version 4.0.0 #685

BozzaDaniel opened this issue Oct 22, 2015 · 44 comments
Milestone

Comments

@BozzaDaniel
Copy link
Contributor

Recently a development version (4.0.0) of Cordova iOS added support for WKWebView with the help of an installable plugin (UIWebView is also a plugin but it's included by default). Read more about everything here: https://shazronatadobe.wordpress.com/2015/09/09/apache-cordova-ios-4-0-0-and-wkwebview-support/

The plugin isn't compatible with the latest API changes (https://github.com/apache/cordova-ios/blob/master/guides/API%20changes%20in%204.0.md), the errors are these:

Incompatible pointer types assigning to 'UIWebView *' from 'UIView * _Nullable'
No known instance method for selector 'initWithWebView:'
No visible @interface for 'UIView' declares the selector 'stringByEvaluatingJavaScriptFromString:'
'Cordova/CDVJSON.h' file not found

Shouldn't be too hard to make it compatible with version 4.0, I can modify the plugin files to fix these myself, but it would be nice to use an unmodified plugin.

@hirbod
Copy link
Contributor

hirbod commented Oct 22, 2015

Please provide a PR if it's that easy. The API changes looking huge, I guess there has to be done some work (writeJavascript, UIWebview, Nsbase64 etc)

@BozzaDaniel
Copy link
Contributor Author

I managed to make the code compile without issues. I encountered an issue with making the map actually appear though as the webpage background stays white.

I've even tried creating a brand new project with Cordova iOS 3.9.1 and the stable version of this plugin to see if there is some issue with the WKWebView but now the background stays white even here. I can't figure out why it's impossible to set a transparent background on the webview anymore.

@hirbod
Copy link
Contributor

hirbod commented Oct 23, 2015

We need to figure out if its possible. I don't have any knowledge about WKWebView.

@hirbod
Copy link
Contributor

hirbod commented Oct 23, 2015

@BozzaDaniel
Copy link
Contributor Author

I managed to get a transparent background of the WKWebView when using the plugin version with a local server on 3.9.1, but when I updated to 4.0.0 and went without the local server I could no longer set the background to transparent. So it should be possible to make the background transparent on a WKWebView.

I tried to create a new Cordova project (3.9.1) and the stable version of this plugin and now it worked to create a transparent background for the WebView. I haven't a clue as why it didn't work earlier.

I will check now if I can get the plugin working with the server version of WKWebView.
Update:
Works! Map renders without any problems. So it will work when using a WKWebView as the actual webview. Now I just need to get it to work with Cordova 4.0.0 and a WKWebView without a local server.

@hirbod
Copy link
Contributor

hirbod commented Oct 23, 2015

Thanks a lot !

@BozzaDaniel
Copy link
Contributor Author

I believe I got it to work with Cordova iOS 4.0.0 and WKWebView plugin without a server. Will try on a clean project next week to see if it works on that too. Next up is enabling all JS stuff again as stringByEvaluatingJavaScriptFromString no longer exists in WKWebView. it should be replaced by evaluateJavascript. Would probably be smart to create a method that is able to switch between the two depending on what is available than littering the code with ifs.

@hirbod
Copy link
Contributor

hirbod commented Oct 23, 2015

Yeah, that would be nice. Thanks for your work, I really appreciate it. My time is very limited.

@BozzaDaniel
Copy link
Contributor Author

I got it working with a clean project too. The fix for the transparency issue is done by using [self.webView [setOpacity:NO]] and [self.webView [setBackgroundColor:[UIColor clearColor]]] in the viewDidLoad method of the viewcontroller displaying the map. Doing it in any other place doesn't seem to work.

I don't know if it's preferable to use self.webViewEngine.engineWebView instead of self.webView on cordova ios 4.0.0 as they've reworked the internals of cordova quite a bit.

@BozzaDaniel
Copy link
Contributor Author

Started working on this again today, and I've found an issue. When working with WKWebViews Cordova has done some changes with the JS bridge communication using postMessage. This causes an error when trying to pass and object with functions. The solution to this is simply to remove the functions that is sent to the native side from all objects.

The biggest issue is the LatLng object that contains 3 functions. they need to be removed in order for anything involving them to work.

Stripping functions shouldn't cause an issue when using UIWebViews as those are ignored by the native side anyway.

@gregavola
Copy link

@BozzaDaniel Any chance you can post your edited googlemaps-cdv-plugin.js file so I take a look at what you edited?

@jaredgreener
Copy link

I am getting a DataCloneError: DOM Exception 25 when adding markers to the map in wkwebview

@BozzaDaniel
Copy link
Contributor Author

@gregavola My quick fix was simply commenting out the functions in the LatLng class. That is a bad idea though so you should probably do something like this, untested:

function delete_from_object( object, type ) {
    var keys = Object.keys(object);
    for( var key in keys ) {
        if ( typeof object[key] === 'object' ) {
            object[key] = delete_from_object( object[key], type );
        } else if ( typeof object[key] === type ) {
            delete object[key];
        }
    }
    return object;
}

Then before doing cordova.exec you'd simply do:

options = delete_from_object( options, 'function' );

@hirbod
Copy link
Contributor

hirbod commented Nov 15, 2015

@BozzaDaniel any progress on this?

@hirbod hirbod closed this as completed Nov 15, 2015
@BozzaDaniel
Copy link
Contributor Author

Stopped working on this for a couple of weeks while working on some other projects. When I return to working on this I will fix everything for the project targeting iOS 8 and above. I've returned to working with a local web server as XHRs to file-urls are still blocked in iOS 9.

@hirbod
Copy link
Contributor

hirbod commented Dec 10, 2015

@BozzaDaniel Cordova iOS 4.0.0 and the wkwebview-engine is out. Would be nice if you could get this plugin work with the new version

@joewoodhouse
Copy link
Contributor

Any update on this @BozzaDaniel ? I really want to try this on my current project (which needs a performance boost!) and I'm happy to start from scratch myself but if you've got some work already done would be good to start from there.

@BozzaDaniel
Copy link
Contributor Author

I've been doing some work on this the past few days, and I've found a way to keep it compatible with both webview types: UIWebView and WKWebView:

First, in all places where a webView is defined as a UIWebView has been changed to a UIView instead (as is the case for Cordova iOS 4.0).
Next up is replacing every stringByEvaluatingJavaScriptFromString with a respondsToSelector and performSelector check. Using stringByEvaluatingJavaScriptFromString for UIWebView and evaluateJavaScript:completionHandler: for WKWebView (completionHandler can be nil).

For places where you are getting a property of the webView (such as request.URL) I'm using an NSInvocation, here is Marker.m:

-(void)setIcon_:(GMSMarker *)marker iconProperty:(NSDictionary *)iconProperty:
   pluginResult:(CDVPluginResult *)pluginResult
     callbackId:(NSString*)callbackId {
// ...
    if (iconPath) {
        NSError *error;
        NSRange range = [iconPath rangeOfString:@"://"];
        if (range.location == NSNotFound) {
            range = [iconPath rangeOfString:@"www/"];
            if (range.location == NSNotFound) {
                range = [iconPath rangeOfString:@"/"];
                if (range.location != 0) {
                    iconPath = [NSString stringWithFormat:@"./%@", iconPath];
                }
            }
        }

        range = [iconPath rangeOfString:@"./"];
        if (range.location != NSNotFound) {
            SEL requestSelector = NSSelectorFromString(@"request");
            SEL urlSelector = NSSelectorFromString(@"URL");
            NSString *currentPath = @"";
            if ([self.mapCtrl.webView respondsToSelector:requestSelector]) {
                NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self.mapCtrl.webView class] instanceMethodSignatureForSelector:requestSelector]];
                [invocation setSelector:requestSelector];
                [invocation setTarget:self.mapCtrl.webView];
                [invocation invoke];
                NSURLRequest *request;
                [invocation getReturnValue:&request];
                currentPath = [request.URL absoluteString];
            } else if ([self.mapCtrl.webView respondsToSelector:urlSelector]) {
                NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self.mapCtrl.webView class] instanceMethodSignatureForSelector:urlSelector]];
                [invocation setSelector:urlSelector];
                [invocation setTarget:self.mapCtrl.webView];
                [invocation invoke];
                NSURL *URL;
                [invocation getReturnValue:&URL];
                currentPath = [URL absoluteString];
            }
// ...

You'd want to use NSInvocation anytime you access a property of the WebView as it's now defined as a UIView instead. You'd have to check the difference between UIWebView and WKWebView properties too.

One final change is the googlemaps-cdv-plugin.js file: Before running any command with cordova.exec run the following on the properties being sent with type being set to function :

function delete_from_object( object, type ) {
    if ( object === null ) return object;
    var keys = Object.keys(object);
    for( var index in keys ) {
       var key = keys[index];
        if ( typeof object[key] === 'object' ) {
            object[key] = delete_from_object( object[key], type );
        } else if ( typeof object[key] === type ) {
            delete object[key];
        }
    }
    return object;
}

run it as so:

options = delete_from_object( options, 'function' );

These should be all the changes needed to get it to work with WKWebViews.

@hirbod
Copy link
Contributor

hirbod commented Jan 5, 2016

So would you like to provide a working PR for that? I'll bounty you 100$ on this

@BozzaDaniel
Copy link
Contributor Author

Give me a few days to do it, I need to setup a new project to do the changes properly.

@joewoodhouse
Copy link
Contributor

@BozzaDaniel Awesome looking forward to it. Should we re-open this issue (not sure why it was ever closed?)

@telemakhos
Copy link

+1 for reopening. This is a critical issue.

@BozzaDaniel
Copy link
Contributor Author

Almost done with the changes on a clean project. The last remaining bit is making the webview transparent again. - (void)webViewDidFinishLoad:(UIWebView*)theWebView; has been removed and I need to find the proper way of doing it now. I already fixed it in my own project as I create webviews in a different ways.

I want to use CDVPageDidLoadNotification, but for some reason it doesn't fire. Will investigate to find out why. A workaround it setting the background color in the getMap method.

@joewoodhouse
Copy link
Contributor

Any update on this? Sorry for being impatient, but I'm really looking forward to this feature! :)

@jvence
Copy link

jvence commented Feb 2, 2016

Same here. This is critical to my app. Any updates

@aesmon
Copy link

aesmon commented Feb 3, 2016

@BozzaDaniel your repo works great on Meteor 1.3 with WkWebView. Are you still working on the plugin? Great work by the way, really amazing.

@gauravarora
Copy link

@BozzaDaniel Sorry for yet another not-so-helpful reminder but is there any chance you're still working on this?

@johnrobertcobbold
Copy link

Just caught up on Cordova4 and this thread. Anything that we can do to help you @BozzaDaniel ?

@aesmon
Copy link

aesmon commented Feb 17, 2016

@jvence BozzaDaniel's repo works great on WkWebView, no problems encountered

@jvence
Copy link

jvence commented Feb 17, 2016

@aesmon Thanks for the update. I guess the following should work:

cordova plugin add https://github.com/BozzaDaniel/cordova-plugin-googlemaps.git --variable API_KEY_FOR_ANDROID="...." --variable API_KEY_FOR_IOS="..." and I should ignore:

"Notice: plugin.google.maps has been automatically converted to cordova-plugin-googlemaps and fetched from npm. This is due to our old plugins registry shutting down."

@hirbod
Copy link
Contributor

hirbod commented Feb 18, 2016

Please use Gitter for that. This isn't a chat - it is an issue tracker. I've deleted non related posts

@denisbabineau
Copy link
Contributor

to avoid the problem mentioned by @jvence (plugin.google.maps has been automatically converted), looks like the plugin/package should be renamed to cordova-plugin-googlemaps to avoid the remapping performed by the cordova-registry-mapper package; I haven't looked up which cordova version introduced this mapper but it prevents doing a plugin add with repo url to test this feature/branch and requires manual/local install.

@twavis
Copy link

twavis commented Feb 19, 2016

I downloaded @BozzaDaniel 's repo locally and changed the id to cordova-plugin-googlemaps and finally was able to build the app in meteor (release 1.3-beta.11) using wkwebview.

The map seems to load but it is white background where map should be. Not sure what to do now.

@aesmon did you change anything else in getting it to work with meteor 1.3?

@aesmon
Copy link

aesmon commented Feb 19, 2016

@twavis From what I recall, I don't think "CDVPageDidLoadNotification" was ever fired in GoogleMaps.m in Meteor 1.3 as it's turned off by default. Either turn it on in Meteor files or paste the pageDidLoad handlers directly into pluginInitialization which seems to not produce any errors for me so far. Also, if you are using any framework like Meteoric Ionic with position absolute views then you will have to set them to transparent manually in JS when initializing the map.

@jsanta
Copy link

jsanta commented Mar 8, 2016

@twavis what did you do to change the plugin id? what files did you change?

I also downloaded @BozzaDaniel 's repo and tried installing it with ionic plugin add /local/repo --variable API_KEY_FOR_ANDROID="..." --variable API_KEY_FOR_IOS="..." but it is going to bitbucket to download the plugin.

@denisbabineau
Copy link
Contributor

@jsanta you can look at my branch which has BozzaDaniel's fork merged in with the latest and the plugin id renamed. I also changed the com.googlemaps.ios dependency commit reference to point to a specific commits (ideally this would point to a tag) since Meteor does not accept branch specs (only hashes and tags to be explicit). Note that with this branch I'm experiencing the white background on IOS issue as well but I haven't looked at the CDVPageDidLoadNotification workaround/fix that BozzaDaniel & easmon mentioned (yet).

@jsanta
Copy link

jsanta commented Mar 9, 2016

Thanks @denisbabineau I'll give it a try.
Best regards.

@jsanta
Copy link

jsanta commented Mar 9, 2016

@denisbabineau seems to work OK, at least the device is showing the map and the app is not complaining because of any errors.

@denisbabineau
Copy link
Contributor

Update: See my comments in Pull #807 to fix whitescreen issues in ios if you need this right away. Hopefully will get merged/pulled soon.

@johnrobertcobbold
Copy link

Is @BozzaDaniel 's repo also working on cordova-ios 4+ with uiwebview ?
EDIT: OK answered my own question, I tried @denisbabineau, using cordova-ios4.0.1 and uiWebView and all is working great. Thanks for that Denis, I can now also upgrade to the latest phonegap-plugin-push which is now requiring cordova-ios 4

ghost pushed a commit that referenced this issue Mar 24, 2016
Merge branch 'master' of https://github.com/BozzaDaniel/cordova-plugin-googlemaps into BozzaDaniel-master

(issue #685)
@wf9a5m75
Copy link
Member

@BozzaDaniel Thank you for your great pull request.

I merged #807 into the master branch. If there is any error that related with #807, please leave the comment here.

@eg271 eg271 mentioned this issue Mar 26, 2016
@wf9a5m75 wf9a5m75 added this to the 1.4.0 milestone Mar 27, 2016
@mscheffer
Copy link

mscheffer commented Jun 16, 2016

i found this thread today, MONTHS after it was started, the problem still seems to be there, unless i'm not getting the correct version ?

(i used the usual command, got version 1.3.9, a 1.4.0 is mentioned here, but the plugin.xml file contains the version number 1.3.9)

@fairport
Copy link

fairport commented Jun 17, 2016

Same here !! Identical situation
Xcode 7.3.1 Cordova 6.2.0

Also getting CDVJSON.h not found

I see 1.4.0 has not been released yet, but I patched in the code changes found here
https://github.com/mapsplugin/cordova-plugin-googlemaps/pull/807/files
and I have a bug free compile now

@hirbod
Copy link
Contributor

hirbod commented Jun 17, 2016

Npm Version has no WKWebview Support. Download directly from master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests