Android开发Android技术知识Android开发经验谈

Hybrid混合开发知识点(一)

2019-02-26  本文已影响15人  正规程序员

Hybrid是半Native半Web开发模式,充分利用H5的跨平台、快速迭代能力以及Native的流畅性、系统API调用能力,具有可复用性高、开发成本低、跨平台开发的特点。

在阐述Hybrid混合开发知识点之前,我们先梳理下WebView加载H5页面及H5与Android的交互等方面的知识点。

WebView常用API及属性配置

WebViewClient类:处理各种通知&请求事件。常用方法如下:

WebChromeClient类:辅助webview处理javaScript对话框,加载进度,网站图标,网站标题等。

WebSettings常用属性:

WebView常用API调用:

Android调用H5

WebView需要设置setJavaScriptEnabled(true);使WebView支持执行JavaScript脚本。

//支持Android 4.4以前的版本,支持页面刷新,但无返回值。
webview.post(new Runnable()){
    @Override
    public void run(){
        webview.loadUrl("javaScript:callJs('params')");
    }   
}

//支持Android 4.4+版本,能接收返回值,不支持页面刷新,调用及回调均在UI线程中。
webview.evaluateJavascipt("javascript:callJS('params')",
    new ValueCallback<String>(){
        @Override
        public void onReceiveValue(String value){
            //处理从js返回的值value
        }   
    });

以上两种Android调用H5方法,均在onPageFinished()方法回调后执行,即页面加载完毕后。

H5调用Android

//为js添加Java映射对象。
webview.addJavascriptInterface(new JsCallAndroid(),"jscallandroid");

public class JsCallAndroid {
    //需添加@JavascriptInterface注解,避免webview漏洞。
    @JavascriptInterface
    public void hello(String msg) {
         System.out.println("JS调用了Android的hello方法");
    }
}

js通过脚本映射addJavascriptInterface()中的Object对象,实现H5调用Android方法。前提须设置settings.setJavaScriptEnabled(true)。

Scheme协议

Android中的Scheme是一种页面跳转协议,常处理以下场景交互:

在使用Scheme前,须在AndroidManifest.xml中对Activity添加< intent-filter/>过滤器注册。

<activity
    android:name=".ui.activity.TestActvity"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateAlwaysHidden|adjustPan">
        <!--Scheme协议配置,intent-filter过滤器支持页面跳转-->
        <intent-filter>
        <!--协议部分,path前须加/,除了sheme外其他选填-->
            <data
                android:host="book"
                android:path="/bookDetail"
                android:port="8888"
                android:scheme="app" />

            <!--下面也要设置-->
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <action android:name="android.intent.action.VIEW" />
        </intent-filter>
</activity>

常规的URL Scheme格式为:[scheme]://[host]/[path]?[query],如 app://book:8888/bookDetail?bookId=10011002

app代表Scheme协议名称,book代表作用域,8888代表端口号(如Http协议的默认端口号为80),bookDetail代表页面路径,bookId代表拼接参数。

App内页面跳转,示例1:

String uri = "app://book:8888/bookDetail?bookId=10011002";
schemeToActivity(uri, 100);

/**
 * 采用Scheme协议页面跳转,校验scheme协议是否有效
 * @param uri
 * @param requestCode
 */
private void schemeToActivity(String uri, int requestCode) {
    if (TextUtils.isEmpty(uri)) return;
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
    List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
    if (activities != null && !activities.isEmpty()) {
        if (requestCode > 0) {
            startActivityForResult(intent, requestCode);
        } else {
            startActivity(intent);
        }
    } else {
        throw new RuntimeException("can not find the activity's URL Scheme");
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    String string = data.getStringExtra("result");
    if (requestCode == 100) {
        Log.d("test", string);
    }
}
/**
 * 解析Scheme协议的uri数据
 */
private void getSchemeIntent() {
    Intent intent = getIntent();
    Uri uri = intent.getData();
    if (uri == null)return;
    String scheme = uri.getScheme();
    String host = uri.getHost();
    int port = uri.getPort();
    String path = uri.getPath();
    List<String> pathSegments = uri.getPathSegments();
    String query = uri.getQuery();
    String bookId = uri.getQueryParameter("bookId");
    Log.d("test",bookId);
}


//退回页面A回传值
Intent intent = new Intent();
intent.putExtra("result","hello world!");
setResult(RESULT_OK,intent);
finish();

通过debug模式,可获得从Scheme中解析出的参数值,如下:


H5页面跳转App页面,示例2:

若要跳转AndroidManifest.xml中定义Scheme的Activity,H5端配置如下:

<a href="app://book:8888/bookDetail?bookId=10011002">图书详情页</a>

在App内点击该WebView页面链接会触发WebViewClient#shouldOverrideUrlLoading()方法,解析如下:

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
       if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                //判定重定向
                WebView.HitTestResult testResult = view.getHitTestResult();
                if (testResult == null ||
                        testResult.getType() == WebView.HitTestResult.UNKNOWN_TYPE) {
                    return false;
                }

                //解析URL Scheme
                Uri uri = request.getUrl();
                //根据schemeToActivity(uri.toString(),0);方案处理跳转
                return true;
        }
        return false;
}

如上所示,和常规的URL Scheme解析同理,注意shouldOverrideUrlLoading()的版本兼容。

重定向问题的处理方案:WebView的getHitTestResult()的函数可以获取点击页面元素的类型,若获取的HitTestResult为null或UNKNOWN_TYPE,则认定为重定向URL,对此情况直接return false。

shouldOverrideUrlLoading()处理H5与Android交互的存在的问题:

硬编码问题虽然借鉴了ARouter路由跳转思想能缓解页面跳转,但是在交互方面addJavascriptInterface映射对象的方案更优。

URL Scheme更适合处理App页面之间的跳转。

上一篇 下一篇

猜你喜欢

热点阅读