Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Good Bye, Javascript Interface!

Tomoaki Imai
November 29, 2016

Good Bye, Javascript Interface!

This slide describes how to handle Javascripts thru webview without using Javascript interface on Android

Tomoaki Imai

November 29, 2016
Tweet

More Decks by Tomoaki Imai

Other Decks in Programming

Transcript

  1. WebSettings settings = webView.getSettings();
 settings.setJavaScriptEnabled(true); webView.addJavascriptInterface(new JavaScriptInterface(activity), “android”); public class

    JavaScriptInterface { public JavascriptInterface(BaseActivity activity){ … this.activity = activity; } @JavascriptInterface
 public void showMessage(String text) { //Call Native method BaseActivity.showMessage(title, text); } } Javascript Interface basic <input type="button" value="test" onClick=“showMessage(‘Potato’,’This is message!')" /> <script type="text/javascript"> function showMessage(title, text) { android.showMessage(title, text); } </script>
  2. WebSettings settings = webView.getSettings();
 settings.setJavaScriptEnabled(true); webView.addJavascriptInterface(new JavaScriptInterface(activity), “android”); public class

    JavaScriptInterface { public JavascriptInterface(BaseActivity activity){ … this.activity = activity; } @JavascriptInterface
 public void showMessage(String text) { //Call Native method BaseActivity.showMessage(title, text); } } Javascript Interface basic <input type="button" value="test" onClick=“showMessage(‘Potato’,’This is message!')" /> <script type="text/javascript"> function showMessage(title, text) { android.showMessage(title, text); } </script>
  3. • Architecture is a black box https://developer.android.com/guide/webapps/webview.html#UsingJavaScript • Thus, hard

    to figure out crashes Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@42249680 is not valid; is your activity running? at com.kouzoh.mercari.util.WebViewUtil$DefaultJavaScriptInterface $2.run(WebViewUtil.java:484) Problems with Javascript Interface
  4. Problems with Javascript Interface • Code complexity on Front end

    <input type="button" value="Say hello" onClick=“showMessage(‘Potato’,’This is message!')" /> <script type="text/javascript"> function showMessage(title, text) { if(client.android){ android.showMessage(title, text); } else if(client.ios){ showMessageForIOS(title, text) } } function showMessageForIOS(title, text){…} </script>
  5. class ViewController: UIViewController, UIWebViewDelegate { //. . . func webView(webView:

    UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { if(request.URL!.scheme == "scheme"){ // … pass to native method return false } return true } how iOS do (using UIWebView)
  6. Evaluating Url • No black box ( just parse Url!)

    • Has consistency with iOS Url evaluation
  7. Basic Architecture 6SJ.PEFM 8FC4DIFNF)BOEMFS $VTUPN8FC$MJFOU /BUJWFNFUIPE scheme://app/showMessage?title=Potato&text=This%20is%20%Message! method: showMessage arguments:

    title=Potato text=This%20is%20%Message! activity.showMessage("Potato", “This is Message!”); shouldOverrideUrloading() parse call
  8. public class UriModel { private final static String SCHEME =

    “scheme://app“
 String method;
 Map<String, String> params = new HashMap<>();
 
 public UriModel(Uri uri) {
 try { 
 String urlData = URLDecoder.decode( uri.toString().substring(SCHEME.length()), "UTF-8");
 urlData = urlData.replaceFirst("\\?", "¥¥");
 String[] splitUrl = urlData.split("¥¥");
 String method = splitUrl[0];
 this.setMethod(method);
 if (splitUrl.length == 1) return;
 
 Set<String> parameterNames = uri.getQueryParameterNames();
 Iterator<String> parameterIterator = parameterNames.iterator();
 
 while (parameterIterator.hasNext()){
 String key = parameterIterator.next();
 this.getParams().put(key, uri.getQueryParameter(key));
 }
 } catch (UnsupportedEncodingException e) {
 }
 } Uri Model Class QBSTFNFUIPE QBSTFQBSBNT
  9. public class CustomWebViewClient extends WebViewClient {
 
 protected WebActivity activity;


    
 
 public CustomWebViewClient(WebActivity activity) {
 super();
 this.activity = activity;
 
 }
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
 
 
 
 
 return false;
 } } Custom WebViewClient
  10. public class CustomWebViewClient extends WebViewClient {
 private final static String

    APP_SCHEME = "scheme.*";
 protected WebActivity activity;
 
 
 public CustomWebViewClient(WebActivity activity) {
 super();
 this.activity = activity;
 
 }
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
 
 
 
 
 return false;
 } } Custom WebViewClient
  11. public class CustomWebViewClient extends WebViewClient {
 private final static String

    APP_SCHEME = "scheme.*";
 protected WebActivity activity;
 WebSchemeHandler schemeHandler;
 
 public CustomWebViewClient(WebActivity activity) {
 super();
 this.activity = activity;
 schemeHandler = new WebSchemeHandler(activity);
 }
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
 
 
 
 
 return false;
 } } Custom WebViewClient
  12. public class CustomWebViewClient extends WebViewClient {
 private final static String

    APP_SCHEME = "scheme.*";
 protected WebActivity activity;
 WebSchemeHandler schemeHandler;
 
 public CustomWebViewClient(WebActivity activity) {
 super();
 this.activity = activity;
 schemeHandler = new WebSchemeHandler(activity);
 }
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
 if (request.getUri().getScheme().matches(APP_SCHEME)){
 schemeHandler.handleUri(view, request.getUri());
 return true;
 }
 return false;
 } } Custom WebViewClient
  13. public class WebSchemeHandler { WebActivity activity; public WebSchemeHandler(WebActivity activity) {


    this.activity = activity;
 } public void handleUri(WebView webView, Uri uri) {
 UriModel uriModel = new UriModel(uri);
 switch (uriModel.getMethod()) {
 case “showMessage": activity.showMessage( uriModel.getParams().get(“title”), uriModel.getParams().get(“text”)); . . . Handle Uri
  14. public class WebSchemeHandler { WebActivity activity; public WebSchemeHandler(WebActivity activity) {


    this.activity = activity;
 } void getDeviceInfo(WebView webView, final String funcName) {
 activity.runOnUiThread(() -> {
 if (webView != null) {
 String deviceInfo = activity.getDeviceInfo(); webView.evaluateJavascript(funcName + "('" + deviceInfo + "')", null);
 }
 });
 } Callbacks to Web
  15. Things to keep in mind • Only allow schemes when

    the web page is secure ‣ Only allow secured(≒ owned) websites ‣ Do not redirect or access to external unknown sites
  16. WebView 2.0?? • From iOS 8.0 ‣ UIWebView -> WKWebView

    • From Android 7.0 ‣ Compatibility issue https://developer.android.com/reference/android/webkit/WebView.html #evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>)