Skip to content

Commit

Permalink
Merge branch 'master' into apacheGH-359-fix-beforeload-POST
Browse files Browse the repository at this point in the history
  • Loading branch information
janpio authored Dec 17, 2018
2 parents a6f2427 + c54d100 commit 1d58272
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 21 deletions.
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ The object returned from a call to `cordova.InAppBrowser.open` when the target i
- __loaderror__: event fires when the `InAppBrowser` encounters an error when loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __beforeload__: event fires when the `InAppBrowser` decides whether to load an URL or not (only with option `beforeload` set).
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.

- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.

Expand All @@ -238,6 +239,7 @@ function showHelp(url) {

inAppBrowserRef.addEventListener('beforeload', beforeloadCallBack);

inAppBrowserRef.addEventListener('message', messageCallBack);
}

function loadStartCallBack() {
Expand All @@ -252,6 +254,13 @@ function loadStopCallBack() {

inAppBrowserRef.insertCSS({ code: "body{font-size: 25px;" });

inAppBrowserRef.executeScript({ code: "\
var message = 'this is the message';\
var messageObj = {my_message: message};\
var stringifiedMessageObj = JSON.stringify(messageObj);\
webkit.messageHandlers.cordova_iab.postMessage(stringifiedMessageObj);"
});

$('#status-message').text("");

inAppBrowserRef.show();
Expand Down Expand Up @@ -300,18 +309,24 @@ function beforeloadCallback(params, callback) {

}

function messageCallback(params){
$('#status-message').text("message received: "+params.data.my_message);
}

```

### InAppBrowserEvent Properties

- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, or `exit`. _(String)_
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message` or `exit`. _(String)_

- __url__: the URL that was loaded. _(String)_

- __code__: the error code, only in the case of `loaderror`. _(Number)_

- __message__: the error message, only in the case of `loaderror`. _(String)_

- __data__: the message contents , only in the case of `message`. A stringified JSON object. _(String)_


### Supported Platforms

Expand All @@ -323,7 +338,11 @@ function beforeloadCallback(params, callback) {

### Browser Quirks

`loadstart` and `loaderror` events are not being fired.
`loadstart`, `loaderror`, `message` events are not fired.

### Windows Quirks

`message` event is not fired.

### Quick Example

Expand All @@ -344,6 +363,7 @@ function beforeloadCallback(params, callback) {
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.

- __callback__: the function to execute when the event fires.
The function is passed an `InAppBrowserEvent` object.
Expand Down
23 changes: 23 additions & 0 deletions src/android/InAppBrowser.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
Expand Down Expand Up @@ -98,6 +99,7 @@ public class InAppBrowser extends CordovaPlugin {
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";
private static final String MESSAGE_EVENT = "message";
private static final String CLEAR_ALL_CACHE = "clearcache";
private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
private static final String HARDWARE_BACK_BUTTON = "hardwareback";
Expand Down Expand Up @@ -954,8 +956,24 @@ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)
settings.setBuiltInZoomControls(showZoomControls);
settings.setPluginState(android.webkit.WebSettings.PluginState.ON);

// Add postMessage interface
class JsObject {
@JavascriptInterface
public void postMessage(String data) {
try {
JSONObject obj = new JSONObject();
obj.put("type", MESSAGE_EVENT);
obj.put("data", new JSONObject(data));
sendUpdate(obj, true);
} catch (JSONException ex) {
LOG.e(LOG_TAG, "data object passed to postMessage has caused a JSON error.");
}
}
}

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
inAppWebView.addJavascriptInterface(new JsObject(), "cordova_iab");
}

String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
Expand Down Expand Up @@ -1369,6 +1387,11 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) {
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);

// Set the namespace for postMessage()
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1){
injectDeferredObject("window.webkit={messageHandlers:{cordova_iab:cordova_iab}}", null);
}

// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush();
Expand Down
30 changes: 27 additions & 3 deletions src/ios/CDVUIInAppBrowser.m
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,16 @@ - (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command
[self.inAppBrowserViewController navigateTo:url];
}

-(void)createIframeBridge
{
// Create an iframe bridge in the new document to communicate with the CDVThemeableBrowserViewController
NSString* jsIframeBridge = @"var e = _cdvIframeBridge=d.getElementById('_cdvIframeBridge'); if(!_cdvIframeBridge) {e = _cdvIframeBridge = d.createElement('iframe'); e.id='_cdvIframeBridge'; e.style.display='none'; d.body.appendChild(e);}";
// Add the postMessage API
NSString* jspostMessageApi = @"window.webkit={messageHandlers:{cordova_iab:{postMessage:function(message){_cdvIframeBridge.src='gap-iab://message/'+encodeURIComponent(message);}}}}";
// Inject the JS to the webview
[self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"(function(d){%@%@})(document)", jsIframeBridge, jspostMessageApi]];
}

// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
// provides a consistent method for injecting JavaScript code into the document.
//
Expand All @@ -352,9 +362,6 @@ - (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command

- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper
{
// Ensure an iframe bridge is created to communicate with the CDVUIInAppBrowserViewController
[self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){_cdvIframeBridge=d.getElementById('_cdvIframeBridge');if(!_cdvIframeBridge) {var e = _cdvIframeBridge = d.createElement('iframe');e.id='_cdvIframeBridge'; e.style.display='none';d.body.appendChild(e);}})(document)"];

if (jsWrapper != nil) {
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:@[source] options:0 error:nil];
NSString* sourceArrayString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
Expand Down Expand Up @@ -492,6 +499,22 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
return NO;
}else if ([scriptCallbackId isEqualToString:@"message"] && (self.callbackId != nil)) {
// Send a message event
NSString* scriptResult = [url path];
if ((scriptResult != nil) && ([scriptResult length] > 1)) {
scriptResult = [scriptResult substringFromIndex:1];
NSError* __autoreleasing error = nil;
NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
if (error == nil) {
NSMutableDictionary* dResult = [NSMutableDictionary new];
[dResult setValue:@"message" forKey:@"type"];
[dResult setObject:decodedResult forKey:@"data"];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dResult];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
}
}
}
}

Expand Down Expand Up @@ -541,6 +564,7 @@ - (void)webViewDidStartLoad:(UIWebView*)theWebView

- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
[self createIframeBridge];
if (self.callbackId != nil) {
// TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected).
NSString* url = [self.inAppBrowserViewController.currentURL absoluteString];
Expand Down
42 changes: 28 additions & 14 deletions src/ios/CDVWKInAppBrowser.m
Original file line number Diff line number Diff line change
Expand Up @@ -584,23 +584,37 @@ - (void)userContentController:(nonnull WKUserContentController *)userContentCont

CDVPluginResult* pluginResult = nil;

NSDictionary* messageContent = (NSDictionary*) message.body;
NSString* scriptCallbackId = messageContent[@"id"];

if([messageContent objectForKey:@"d"]){
NSString* scriptResult = messageContent[@"d"];
NSError* __autoreleasing error = nil;
NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult];
if([message.body isKindOfClass:[NSDictionary class]]){
NSDictionary* messageContent = (NSDictionary*) message.body;
NSString* scriptCallbackId = messageContent[@"id"];

if([messageContent objectForKey:@"d"]){
NSString* scriptResult = messageContent[@"d"];
NSError* __autoreleasing error = nil;
NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION];
}
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
}else if(self.callbackId != nil){
// Send a message event
NSString* messageContent = (NSString*) message.body;
NSError* __autoreleasing error = nil;
NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[messageContent dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
if (error == nil) {
NSMutableDictionary* dResult = [NSMutableDictionary new];
[dResult setValue:@"message" forKey:@"type"];
[dResult setObject:decodedResult forKey:@"data"];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dResult];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
}
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]];
}

[self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
}

- (void)didStartProvisionalNavigation:(WKWebView*)theWebView
Expand Down
27 changes: 27 additions & 0 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
var cordova = require('cordova');
var isWindows = cordova.platformId === 'windows';
var isIos = cordova.platformId === 'ios';
var isAndroid = cordova.platformId === 'android';
var isBrowser = cordova.platformId === 'browser';

window.alert = window.alert || navigator.notification.alert;
Expand Down Expand Up @@ -151,6 +152,32 @@ exports.defineAutoTests = function () {
done();
});
});

it('inappbrowser.spec.7 should support message event', function (done) {
if (!isAndroid && !isIos) {
return pending(cordova.platformId + ' platform doesn\'t support message event');
}
var messageKey = 'my_message';
var messageValue = 'is_this';
iabInstance = cordova.InAppBrowser.open(url, '_blank', platformOpts);
iabInstance.addEventListener('message', function (evt) {
// Verify message event
expect(evt).toBeDefined();
expect(evt.type).toEqual('message');
expect(evt.data).toBeDefined();
expect(evt.data[messageKey]).toBeDefined();
expect(evt.data[messageKey]).toEqual(messageValue);
done();
});
iabInstance.addEventListener('loadstop', function (evt) {
var code = '(function(){\n' +
' var message = {' + messageKey + ': "' + messageValue + '"};\n' +
' webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify(message));\n' +
'})()';
iabInstance.executeScript({ code: code });
});

});
});
};
if (isIos) {
Expand Down
2 changes: 1 addition & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright (c) Microsoft Open Technologies Inc
// Licensed under the MIT license.
// TypeScript Version: 2.3
type channel = "loadstart" | "loadstop" | "loaderror" | "exit";
type channel = "loadstart" | "loadstop" | "loaderror" | "exit" | "message";

interface Window {
/**
Expand Down
3 changes: 2 additions & 1 deletion www/inappbrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
'loadstop': channel.create('loadstop'),
'loaderror': channel.create('loaderror'),
'exit': channel.create('exit'),
'customscheme': channel.create('customscheme')
'customscheme': channel.create('customscheme'),
'message': channel.create('message')
};
}

Expand Down

0 comments on commit 1d58272

Please sign in to comment.