Upload
ayman-mahfouz
View
35
Download
3
Embed Size (px)
Citation preview
Hybrid Apps and Qortoba: Your own mini-Cordova
Ayman MahfouzVP of Engineering @ Webalo
December 2016
Agenda
- Bio- Problem Context- Introducing Hybrid Apps- Native-to-JS communication- Project Qortoba- Q&A
Native Apps
Pros
● Performance● Security● Familiarity● Access to Device
Cons
● Portability● Maintenance● Time to Market
So?
Native Apps - Shared Code
Shared Java code allows for extensibility, but how to open the Webalo Client up for third party extension?
Solution - Hybrid App
Java / Obj-C
WebViewHTML + JS
?
The Matrix!
Native to JavaScript
Android
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
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).
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
Native to JavaScript
iOS
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
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
Objective-C to JavaScript - Notes
- (void) viewDidLoad {
// Send page load request to Web View
}
- (void) webViewDidFinishLoad : (UIWebView *)webView {
// Ask Web View to evaluate JavaScript
}
Back to the Matrix!
JavaScript to Native
Android
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
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 } }); }
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
JavaScript to Native
iOS
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
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¶m2=3
Obj
ectiv
e-C
JS
The Matrix Reloaded!
Project Qortoba
Cordova (Qortoba) - Spain
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
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
linkedin.com/in/amahfouz
github.com/amahfouz
Questions
amahfouz.github.io
slideshare.net/AymanMahfouz