+ [android] support communication between weex and web

Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/fbaffef2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/fbaffef2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/fbaffef2

Branch: refs/heads/master
Commit: fbaffef2e304448761a494451f505cf2c6c04bc9
Parents: 4a3b952
Author: 南麓 <haonan....@alibaba-inc.com>
Authored: Wed Mar 7 19:09:53 2018 +0800
Committer: misakuo <misa...@apache.org>
Committed: Tue Mar 20 12:36:08 2018 +0800

----------------------------------------------------------------------
 .../java/com/taobao/weex/common/Constants.java  |   6 +-
 .../com/taobao/weex/ui/component/WXWeb.java     |  42 +++++-
 .../taobao/weex/ui/module/WXWebViewModule.java  |  21 ++-
 .../java/com/taobao/weex/ui/view/IWebView.java  |   7 +
 .../java/com/taobao/weex/ui/view/WXWebView.java | 138 ++++++++++++++++++-
 5 files changed, 201 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fbaffef2/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java 
b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
index a994663..4873f1f 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
+++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
@@ -108,6 +108,7 @@ public class Constants {
     String FILTER = "filter";
     String QUALITY = "quality";
     String SRC = "src";
+    String SOURCE = "source";
     String PLACE_HOLDER = "placeHolder";
     String RESIZE_MODE = "resizeMode";
     String AUTO_RECYCLE = "autoBitmapRecycle";
@@ -326,11 +327,8 @@ public class Constants {
       String DESTORY = "destroy";
     }
 
-
     String STOP_PROPAGATION = "stopPropagation";
-
-
-
+    String ONMESSAGE = "message";
   }
 
   public interface PSEUDO {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fbaffef2/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
index d2fe72b..81c649a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
@@ -25,6 +25,7 @@ import android.text.TextUtils;
 import android.view.View;
 
 import com.taobao.weex.WXSDKInstance;
+import com.taobao.weex.WXSDKManager;
 import com.taobao.weex.annotation.Component;
 import com.taobao.weex.adapter.URIAdapter;
 import com.taobao.weex.common.Constants;
@@ -42,6 +43,7 @@ public class WXWeb extends WXComponent {
     public static final String GO_BACK = "goBack";
     public static final String GO_FORWARD = "goForward";
     public static final String RELOAD = "reload";
+    public static final String POST_MESSAGE = "postMessage";
     protected IWebView mWebView;
 
     @Deprecated
@@ -96,6 +98,14 @@ public class WXWeb extends WXComponent {
                 }
             }
         });
+        mWebView.setOnMessageListener(new IWebView.OnMessageListener() {
+            @Override
+            public void onMessage(Object msg) {
+                Map<String, Object> params = new HashMap<>();
+                params.put("data", msg);
+                fireEvent(Constants.Event.ONMESSAGE, params);
+            }
+        });
         return mWebView.getView();
     }
 
@@ -118,6 +128,11 @@ public class WXWeb extends WXComponent {
                 if (src != null)
                     setUrl(src);
                 return true;
+            case Constants.Name.SOURCE:
+                String source = WXUtils.getString(param,null);
+                if (source != null)
+                    setSource(source);
+                return true;
         }
         return super.setProperty(key,param);
     }
@@ -137,7 +152,14 @@ public class WXWeb extends WXComponent {
         }
     }
 
-    public void setAction(String action) {
+    @WXComponentProp(name = Constants.Name.SOURCE)
+    public void setSource(String source) {
+        if (!TextUtils.isEmpty(source) && getHostView() != null) {
+            loadDataWithBaseURL(source);
+        }
+    }
+
+    public void setAction(String action, Object data) {
         if (!TextUtils.isEmpty(action)) {
             if (action.equals(GO_BACK)) {
                 goBack();
@@ -145,6 +167,8 @@ public class WXWeb extends WXComponent {
                 goForward();
             } else if (action.equals(RELOAD)) {
                 reload();
+            } else if (action.equals(POST_MESSAGE)) {
+                postMessage(data);
             }
         }
     }
@@ -162,6 +186,18 @@ public class WXWeb extends WXComponent {
         getWebView().loadUrl(url);
     }
 
+    private void loadDataWithBaseURL(String source) {
+        String baseUrl = null;
+        try {
+            String bundleUrl = 
WXSDKManager.getInstance().getSDKInstance(getInstanceId()).getBundleUrl();
+            Uri uri = Uri.parse(bundleUrl);
+            baseUrl = uri.getScheme() + "://" + uri.getAuthority();
+        } catch (Exception e) {
+            // do noting
+        }
+        getWebView().loadDataWithBaseURL(source, baseUrl);
+    }
+
     private void reload() {
         getWebView().reload();
     }
@@ -174,6 +210,10 @@ public class WXWeb extends WXComponent {
         getWebView().goBack();
     }
 
+    private void postMessage(Object msg) {
+        getWebView().postMessage(msg);
+    }
+
     private IWebView getWebView() {
         return mWebView;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fbaffef2/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
index 5e058b9..9878c85 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
@@ -29,7 +29,8 @@ public class WXWebViewModule extends WXModule{
     private enum Action {
         reload,
         goBack,
-        goForward
+        goForward,
+        postMessage
     }
 
     @JSMethod(uiThread = true)
@@ -47,15 +48,23 @@ public class WXWebViewModule extends WXModule{
         action(Action.reload, ref);
     }
 
-    private void action(Action action, String ref) {
+    @JSMethod(uiThread = true)
+    public void postMessage(String ref, Object msg) {
+        action(Action.postMessage, ref, msg);
+    }
 
+    private void action(Action action, String ref, Object data) {
         WXComponent webComponent =
-                WXSDKManager.getInstance()
-                        .getWXRenderManager()
-                        .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
+            WXSDKManager.getInstance()
+                .getWXRenderManager()
+                .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
         if(webComponent instanceof WXWeb) {
-            ((WXWeb) webComponent).setAction(action.name());
+            ((WXWeb) webComponent).setAction(action.name(), data);
         }
     }
 
+    private void action(Action action, String ref) {
+        action(action, ref, null);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fbaffef2/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
index 9b3f0c7..5b0d332 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
@@ -24,12 +24,15 @@ public interface IWebView {
     public View getView();
     public void destroy();
     public void loadUrl(String url);
+    public void loadDataWithBaseURL(String source, String baseUrl);
     public void reload();
     public void goBack();
     public void goForward();
+    public void postMessage(Object msg);
     public void setShowLoading(boolean shown);
     public void setOnErrorListener(OnErrorListener listener);
     public void setOnPageListener(OnPageListener listener);
+    public void setOnMessageListener(OnMessageListener listener);
 
     public interface OnErrorListener {
         public void onError(String type, Object message);
@@ -40,4 +43,8 @@ public interface IWebView {
         public void onPageStart(String url);
         public void onPageFinish(String url, boolean canGoBack, boolean 
canGoForward);
     }
+
+    public interface OnMessageListener {
+        public void onMessage(Object msg);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fbaffef2/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
index 68fac88..14a0ace 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
@@ -21,11 +21,19 @@ package com.taobao.weex.ui.view;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.net.Uri;
 import android.net.http.SslError;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
 import android.support.annotation.Nullable;
+import android.text.TextUtils;
 import android.view.Gravity;
 import android.view.View;
+import android.webkit.JavascriptInterface;
+import android.webkit.JsPromptResult;
 import android.webkit.SslErrorHandler;
+import android.webkit.ValueCallback;
 import android.webkit.WebChromeClient;
 import android.webkit.WebResourceError;
 import android.webkit.WebResourceRequest;
@@ -36,18 +44,29 @@ import android.webkit.WebViewClient;
 import android.widget.FrameLayout;
 import android.widget.ProgressBar;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
 import com.taobao.weex.utils.WXLogUtils;
 
+import java.lang.ref.WeakReference;
+
 public class WXWebView implements IWebView {
 
     private Context mContext;
     private WebView mWebView;
     private ProgressBar mProgressBar;
     private boolean mShowLoading = true;
+    private Handler mMessageHandler;
+    private static final int POST_MESSAGE = 1;
+    private static final String BRIDGE_NAME = "__WEEX_WEB_VIEW_BRIDGE";
+    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
+    // downgraded by 
CVE-2012-6636(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6636)
+    private static final boolean DOWNGRADE_JS_INTERFACE = SDK_VERSION < 17;
 
     private OnErrorListener mOnErrorListener;
     private OnPageListener mOnPageListener;
-
+    private OnMessageListener mOnMessageListener;
 
     public WXWebView(Context context) {
         mContext = context;
@@ -75,6 +94,9 @@ public class WXWebView implements IWebView {
         mProgressBar.setLayoutParams(pLayoutParams);
         pLayoutParams.gravity = Gravity.CENTER;
         root.addView(mProgressBar);
+
+        mMessageHandler = new MessageHandler(this);
+
         return root;
     }
 
@@ -95,6 +117,12 @@ public class WXWebView implements IWebView {
     }
 
     @Override
+    public void loadDataWithBaseURL(String source, String baseUrl) {
+        if (mWebView == null) return;
+        mWebView.loadDataWithBaseURL(baseUrl, source, "text/html", "utf-8", 
null);
+    }
+
+    @Override
     public void reload() {
         if(getWebView() == null)
             return;
@@ -115,6 +143,30 @@ public class WXWebView implements IWebView {
         getWebView().goForward();
     }
 
+    @Override
+    public void postMessage(Object msg) {
+        if(getWebView() == null)
+            return;
+
+        try {
+            JSONObject jsonMsg = new JSONObject();
+            jsonMsg.put("data", msg);
+            evaluateJS("javascript:(function () {" +
+                "var event;" +
+                "var data = " + jsonMsg.toString() + ";" +
+                "try {" +
+                "event = new MessageEvent('message', data);" +
+                "} catch (e) {" +
+                "event = document.createEvent('MessageEvent');" +
+                "event.initMessageEvent('message', true, true, data.data, 
data.origin, data.lastEventId, data.source);" +
+                "}" +
+                "document.dispatchEvent(event);" +
+                "})();");
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /*@Override
     public void setVisibility(int visibility) {
         if (mRootView != null) {
@@ -137,6 +189,11 @@ public class WXWebView implements IWebView {
         mOnPageListener = listener;
     }
 
+    @Override
+    public void setOnMessageListener(OnMessageListener listener) {
+        mOnMessageListener = listener;
+    }
+
     private void showProgressBar(boolean shown) {
         if (mShowLoading) {
             mProgressBar.setVisibility(shown ? View.VISIBLE : View.GONE);
@@ -185,6 +242,13 @@ public class WXWebView implements IWebView {
                 if (mOnPageListener != null) {
                     mOnPageListener.onPageFinish(url, view.canGoBack(), 
view.canGoForward());
                 }
+                if (mOnMessageListener != null) {
+                    evaluateJS("javascript:(window.postMessage = 
function(data) {"
+                        + (DOWNGRADE_JS_INTERFACE
+                        ? "prompt('" + BRIDGE_NAME + "://postMessage?data=' + 
JSON.stringify(data))"
+                        : BRIDGE_NAME + ".postMessage(JSON.stringify(data));")
+                        + "})");
+                }
             }
 
             @Override
@@ -211,7 +275,6 @@ public class WXWebView implements IWebView {
                     mOnErrorListener.onError("error", "ssl error");
                 }
             }
-
         });
         wv.setWebChromeClient(new WebChromeClient() {
             @Override
@@ -230,7 +293,78 @@ public class WXWebView implements IWebView {
                 }
             }
 
+            @Override
+            public boolean onJsPrompt(WebView view, String url, String 
message, String defaultValue, JsPromptResult result) {
+                Uri uri = Uri.parse(message);
+                String scheme = uri.getScheme();
+                if (TextUtils.equals(scheme, BRIDGE_NAME)) {
+                    if (TextUtils.equals(uri.getAuthority(), "postMessage")) {
+                        String data = uri.getQueryParameter("data");
+                        onMessage(data);
+                        result.confirm("success");
+                    } else {
+                        result.confirm("fail");
+                    }
+                    return true;
+                }
+                return super.onJsPrompt(view, url, message, defaultValue, 
result);
+            }
         });
+        if (!DOWNGRADE_JS_INTERFACE) {
+            wv.addJavascriptInterface(new Object() {
+                @JavascriptInterface
+                public void postMessage(String data) {
+                    onMessage(data);
+                }
+            }, BRIDGE_NAME);
+        }
+    }
+
+    private void onMessage(String data) {
+        if (data != null && mOnMessageListener != null) {
+            try {
+                Message message = new Message();
+                message.what = POST_MESSAGE;
+                message.obj = JSON.parse(data);
+                mMessageHandler.sendMessage(message);
+            } catch (JSONException e) {
+                throw new RuntimeException(e);
+            }
+
+        }
     }
 
+    private void evaluateJS(String jsStr) {
+        if (SDK_VERSION < 19) {
+            mWebView.loadUrl(jsStr);
+        } else {
+            mWebView.evaluateJavascript(jsStr, new ValueCallback<String>() {
+                @Override
+                public void onReceiveValue(String value) {
+                }
+            });
+        }
+    }
+
+    private static class MessageHandler extends Handler {
+        private final WeakReference<WXWebView> mWv;
+
+        private MessageHandler(WXWebView wv) {
+            mWv = new WeakReference<>(wv);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+                case POST_MESSAGE:
+                    if (mWv.get() != null && mWv.get().mOnMessageListener != 
null) {
+                        mWv.get().mOnMessageListener.onMessage(msg.obj);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
 }

Reply via email to