Gdg dev fest hybrid apps your own mini-cordova

28
Hybrid Apps and Qortoba: Your own mini-Cordova Ayman Mahfouz VP of Engineering @ Webalo December 2016

Transcript of Gdg dev fest hybrid apps your own mini-cordova

Page 1: Gdg dev fest hybrid apps  your own mini-cordova

Hybrid Apps and Qortoba: Your own mini-Cordova

Ayman MahfouzVP of Engineering @ Webalo

December 2016

Page 2: Gdg dev fest hybrid apps  your own mini-cordova

Agenda

- Bio- Problem Context- Introducing Hybrid Apps- Native-to-JS communication- Project Qortoba- Q&A

Page 3: Gdg dev fest hybrid apps  your own mini-cordova

Problem Context - Webalo Platform

www.webalo.com

Page 4: Gdg dev fest hybrid apps  your own mini-cordova

Native Apps

Pros

● Performance● Security● Familiarity● Access to Device

Cons

● Portability● Maintenance● Time to Market

So?

Page 5: Gdg dev fest hybrid apps  your own mini-cordova

Native Apps - Shared Code

Shared Java code allows for extensibility, but how to open the Webalo Client up for third party extension?

Page 6: Gdg dev fest hybrid apps  your own mini-cordova

Solution - Hybrid App

Java / Obj-C

WebViewHTML + JS

?

Page 7: Gdg dev fest hybrid apps  your own mini-cordova

The Matrix!

Page 8: Gdg dev fest hybrid apps  your own mini-cordova

Native to JavaScript

Android

Page 9: Gdg dev fest hybrid apps  your own mini-cordova

Java to JavaScript

API

void evaluateJavascript(String script, ValueCallback<String> resultCallback)

webView.evaluateJavascript(“someJavaScriptFunction();”, new ValueCallback<String>() {

public void onReceiveValue(String s) { JsonReader reader = new JsonReader(new StringReader(s));

JsonToken token = JsonReader.peek() ... }});

Usage

Page 10: Gdg dev fest hybrid apps  your own mini-cordova

Java to JavaScript - Notes

Requirements

1. API level 19.2. WebSettings.setJavaScriptEnabled(true) // false by default3. Must be called on UI thread.

evaluateJavascript(...)

Properties

1. Asynchronous evaluation.2. Context of currently displayed page.3. Callback made on UI thread.4. Callback value is a JSON object. To pass String values use

JsonReader.setLenient(true).

Page 11: Gdg dev fest hybrid apps  your own mini-cordova

Java to JavaScript - Pre 19

void loadUrl(String url)

Usage

webView.loadUrl(“javascript:someJsFunction();”);

API

Pitfall - Navigate away

webView.loadUrl(“javascript:someJsFunction();void(0);”);

No return value!

[INFO:CONSOLE(1)] "Uncaught SyntaxError: Unexpected token ILLEGAL", source: (1)

Common error

Page 12: Gdg dev fest hybrid apps  your own mini-cordova

Native to JavaScript

iOS

Page 13: Gdg dev fest hybrid apps  your own mini-cordova

Objective-C to JavaScript

WKWebView API (iOS 8+)

- (void)evaluateJavaScript : (NSString *)javaScriptString completionHandler : (void (^)(id, NSError *error))completionHandler;

[webView evaluateJavaScript : script completionHandler:^(id result, NSError *error) { if (error == nil) { if (result != nil) { NSString* resultString = [NSString stringWithFormat:@"%@", result]; ... } } else { NSLog(@"evaluateJavaScript error : %@", error.localizedDescription); } }];

Usage

Page 14: Gdg dev fest hybrid apps  your own mini-cordova

Objective-C to JavaScript - Pre iOS 8

UIWebView API

- (NSString *)stringByEvaluatingJavaScriptFromString : (NSString *)script;

NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

NSString *ten = [webView stringByEvaluatingJavaScriptFromString:@"var x = 2; x * 5;"];

Usage

Page 15: Gdg dev fest hybrid apps  your own mini-cordova

Objective-C to JavaScript - Notes

- (void) viewDidLoad {

// Send page load request to Web View

}

- (void) webViewDidFinishLoad : (UIWebView *)webView {

// Ask Web View to evaluate JavaScript

}

Page 16: Gdg dev fest hybrid apps  your own mini-cordova

Back to the Matrix!

Page 17: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Native

Android

Page 18: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Java

Inject objects into the displayed page context:

private final class Api {

public void showMessage(String message) { Log.d(TAG, message); }}webView.addJavascriptInterface(new Api(), "MyJavaObj");

Starting API 17

void addJavascriptInterface(Object serviceApi, String name)

Usage

API

MyJavaObj.showMessage(“Hello There!”);

Java

JS

@JavascriptInterface

Page 19: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Java - Notes

1. Injected objects will not appear in JavaScript until the page is next (re)loaded.

webView.loadData("", "text/html", null);

2. WebView interacts with Java object on a background thread. 3. Serialization of arguments

a. Simple types and stringsb. Serialize objects as JSON

4. Use WebChromeClient to handle callbacks

webView.setWebChromeClient(new WebChromeClient() { public boolean onJsAlert(...) { // display alert in OS theme } }); }

Page 20: Gdg dev fest hybrid apps  your own mini-cordova

Troubleshooting

Use Chrome “Inspect” feature

chrome://inspectMust enable debugging

WebView.setWebContentsDebuggingEnabled(true);

android.view.ViewRootImpl$CalledFromWrongThreadException[INFO:CONSOLE(13)] "Uncaught ReferenceError: MyJavaObj is not defined"

1. Run calls from JavaScript on UI Thread. 2. Invoked too early

a. Wait till page loads WebViewClient.onPageFinished()b. May need call to force page load using

webView.loadData("", "text/html", null);

Debugging

Common Causes

Common Errors

Page 21: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Native

iOS

Page 22: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Objective-C

Inject an object into WK

@interface MyHandler : NSObject<WKScriptMessageHandler> { … }

- (void)userContentController : (WKUserContentController *)userContentController didReceiveScriptMessage: (WKScriptMessage *)message { NSDictionary *dict = (NSDictionary*)message.body; NSString *str = [dict objectForKey:@"strField"]; NSNumber *num = [dict objectForKey:@"numField"]; ...}

[webView.configuration.userContentController addScriptMessageHandler : myHandlerObject

name : @"handlerNameInJs"];

Usage

API

window.webkit.messageHandlers.handlerNameInJs.postMessage( { ‘strField’ : “Some string value”, ‘numField’ : 3 } );

Obj

ectiv

e-C

JS

Page 23: Gdg dev fest hybrid apps  your own mini-cordova

JavaScript to Objective-C - Pre iOS 8

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest : (NSURLRequest *)request navigationType : (UIWebViewNavigationType)navigationType {

NSURL* url = request.URL;

if ( ! [url.scheme isEqualToString:@"myapp"]) { return YES; }

// decode the invocation

NSString* methodName = [hostStrEncoded stringByRemovingPercentEncoding]; NSString* queryStr = [[url query] stringByRemovingPercentEncoding]; ... return NO;}

Usage - UIWebViewDelegate

Point the browser to the function you want to invoke!API

document.location.href = “myapp://methodName?param1=test&param2=3

Obj

ectiv

e-C

JS

Page 24: Gdg dev fest hybrid apps  your own mini-cordova

The Matrix Reloaded!

Page 25: Gdg dev fest hybrid apps  your own mini-cordova

Project Qortoba

Cordova (Qortoba) - Spain

Page 26: Gdg dev fest hybrid apps  your own mini-cordova

Features

● Utilities for JavaScript-to-Native communications.● Unified OS-version-independent interface.● Strongly-typed Java interfaces proxying JavaScript.● Hide UIWebView delegate implementation.● Scripts for generating JavaScript classes.● Communication with AngularJS services.

Project Qortoba

github.com/amahfouz/qortoba

Page 27: Gdg dev fest hybrid apps  your own mini-cordova

Extensions

● Callbacks for JavaScript-to-Native.● Handling object graphs.● Object parameter serialization.● More code generation scripts.● Better error handling.● Platforms other than Android and iOS.

Project Qortoba

github.com/amahfouz/qortoba