• Android与H5交互 -- 点击H5跳转到 Android原生 页面


    Android与H5交互

    app开发过程中,利用原生+h5模式来开发是比较常见的
    下面案例演示的是:原生调起一个H5页面,然后H5点击跳转到原生

    WebViewActivity页面 调用H5 ,点击H5链接 跳转到原生MainActivity页面

    注意 别忘了

    <uses-permission android:name="android.permission.INTERNET" />
    
    • 1
    一、清单文件,增加的配置
    • data的数据就是H5 A标签 href=“#”填写的链接地址: android://h5/open
      在这里插入图片描述
    二、在你需要跳转的页面,清单文件中加入如下配置:
    <activity android:name=".MainActivity" android:exported="true">
                <!-- h5跳转app -->
                <!-- 需要添加下面的intent-filter配置 -->
                <intent-filter>
                    <!-- 通过一个应用来显示数据 -->
                    <action android:name="android.intent.action.VIEW" />
                    <!-- 默认值,没有该默认值则无法响应隐式意图 -->
                    <category android:name="android.intent.category.DEFAULT" />
                    <!-- 该组件可以通过浏览器打开 -->
                    <category android:name="android.intent.category.BROWSABLE" />
                    <!-- android:scheme="android"    用来辨别启动的app -->
                    <!-- android:host="h5"           可以当成是一个域名,这边建议使用应用的包名 -->
                    <!-- android:pathPrefix="/open"  参数路径前缀 -->
                    <data
                        android:host="h5"
                        android:pathPrefix="/open"
                        android:scheme="android" /><!-- android://h5/open -->
                </intent-filter>
            </activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    三、整体结构布局如下 :
    四、贴一下html里面的代码吧
    • ceshi.html
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title>测试</title>
    	</head>
    	<body>
    		<a href="android://h5/open?type=5&id=2" style="font-size: 55px;">点击事件1</a>
    		<br />
    		<br />
    		<a href="file:///android_asset/cs.html" style="font-size: 55px;">点击事件2</a>
    		<br />
    		<br />
    	</body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • cs.html
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title>测试</title>
    	</head>
    	<body>
    		<br />
    		<a href="file:///android_asset/ceshi.html" style="font-size: 55px;" >点击事件2</a>
    		<br />
    	</body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    五、具体实现如下:
    • activity_web_view.xml
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".WebViewActivity">
        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    </RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • WebViewActivity页面的处理

    调用的是本地H5(html)路径

    package com.example.myapplication;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Bundle;
    import android.text.TextUtils;
    import android.util.Log;
    import android.webkit.WebSettings;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    
    public class WebViewActivity extends AppCompatActivity {
        private WebView webView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_web_view);
            initwebView();//初始化webview
        }
    
        @SuppressLint("JavascriptInterface")
        private void initwebView() {
            webView = (WebView) findViewById(R.id.webView);
            WebSettings webSettings = webView.getSettings();
            webSettings.setDomStorageEnabled(true);
            //设置WebView属性,能够执行Javascript脚本
            webSettings.setJavaScriptEnabled(true);
            //设置可以访问文件
            webSettings.setAllowFileAccess(true);
            //设置Web视图
            webView.setWebViewClient(new WebViewClient(){
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                    WebView.HitTestResult hit = view.getHitTestResult();
                    //hit.getExtra()为null或者hit.getType() == 0都表示即将加载的URL会发生重定向,需要做拦截处理
                    if (TextUtils.isEmpty(hit.getExtra()) || hit.getType() == 0) {
                        //通过判断开头协议就可解决大部分重定向问题了,有另外的需求可以在此判断下操作
                        Log.e("重定向", "重定向: " + hit.getType() + " && EXTRA()" + hit.getExtra() + "------");
                        Log.e("重定向", "GetURL: " + view.getUrl() + "\n" + "getOriginalUrl()" + view.getOriginalUrl());
                        Log.d("重定向", "URL: " + url);
                    }
                    if (url.startsWith("http://") || url.startsWith("https://")) { //加载的url是http/https协议地址
                        view.loadUrl(url);
                        return false; //返回false表示此url默认由系统处理,url未加载完成,会继续往下走
    
                    } else { //加载的url是自定义协议地址
                        try {
                            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                            if (intent.resolveActivity(WebViewActivity.this.getPackageManager())!=null){
                                startActivity(intent);
                            }
    
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        return true;
                    }
                }
                //开始加载网络
                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                    Log.e("加载中",url);
                }
                //网页加载完成回调
                @SuppressLint("NewApi")
                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                    Log.e("加载完成",url);
                }
            });
            // 调用本地H5页面的方法
            webView.loadUrl("file:///android_asset/ceshi.html");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    以上是运行跳转成功,下面是拿到跳转的参数

    • MainActivity
    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = getIntent();
            Log.d("test123",""+intent);
            String action = intent.getAction();
            if (Intent.ACTION_VIEW.equals(action)) { //判断是否是我们指定的 action
                Uri uri = intent.getData(); //将String类型的URL转变为URI
                if (uri != null) {
                    String type = uri.getQueryParameter("type"); //获取参数
                    String id = uri.getQueryParameter("id");
                    Log.d("uri", "" + uri);
                    Log.d("type", "" + type);
                    Log.d("id", "" + id);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 跳转第二个页面后,获取的参数打印如下:
      在这里插入图片描述

    Android webview调用JS方法

    • Android写一个触发事件(button),调用AndroidJsCall();
      resule是传递的参数
        @SuppressLint("SetJavaScriptEnabled")
        public void AndroidJsCall()
        {
            webView.loadUrl("javascript:toAndroidCall('"+resule+"')");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • h5(vue)中写一个方法
    • html如下:
     function toAndroidCall(message){
    			console.log("Android中调用JS方法成功,做处理---------------"+message);
            }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    • vue如下:
    mounted() {
        //将要给原生调用的方法挂载到 window 上面
        window.callJsFunction = this.callJsFunction
    },
    methods: {
        callJsFunction(message) {
            console.log("Android中调用JS方法成功,做处理---------------"+message);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    JS中调用Android webview方法

    • 1、webView进行配置
            //增加JS接口
            webView.addJavascriptInterface(this,"ceshi");
    
    • 1
    • 2
    • 2、Android中实现方法
        //JS调用Android方法
        @JavascriptInterface
        public String jsCallAndroid(){
            Toast.makeText(this,"JS调用Android方法成功",Toast.LENGTH_LONG).show();
            return result;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果要传参数

        //JS调用Android方法-带参数
        @JavascriptInterface
        public String jsCallAndroid(int type){
            Toast.makeText(this,"JS调用Android方法成功,type----"+type,Toast.LENGTH_LONG).show();
            return result;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 3、在JS中新增一个按钮
    <button id="button" onclick="toCallAndroid()">JS调用Android方法</button>
    
    • 1
    • 4、设置点击事件
            //JS中调用Android方法
            function toCallAndroid()
            {
                ceshi.jsCallAndroid();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    安卓响应前端选择文件照片 input type=“file“

    不响应: H5 访问本地文件的时候,使用的 ,WebView 出于安全性的考虑,限制了以上操作。
    解决实现:webview 中重写方法响应 WebviewChromeClient 。

    • 4.1以上系统,使用 openFileChooser() ,该方法5.0已经被废弃
    • 5.0以上系统,使用 onShowFileChooser()
    	private ValueCallback<Uri[]> uploadMessageAboveL;
    	private ValueCallback<Uri[]> uploadMessage;
        //用于保存拍照图片的uri
        private Uri mCameraUri;
        private static final int CAMERA_REQUEST_CODE = 10010;//相机标识符
        private static final int ACTION_CHOOSE_IMAGE = 0x201;//相册标识符
    
    
    webView.setWebChromeClient(new WebChromeClient(){
    			//Android  >= 5.0
                @Override
                public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                    uploadMessageAboveL = filePathCallback;
                    //调用系统相机或者相册
                    uploadPicture();
                    return true;
                }
                //For Android  >= 4.1
                public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture)
                   uploadMessage = filePathCallback;
                    //调用系统相机或者相册
                    uploadPicture();
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 我这里是给个弹框选择 拍照 还是 调用系统相册
      在这里插入图片描述
    	 private static String[] items = new String[]{
                "拍照",
                "从相册中选择",
                "取消",
        };
        private void uploadPicture() {
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("请选择图片");
            builder.setItems(items, new DialogInterface.OnClickListener() {
                @RequiresApi(api = Build.VERSION_CODES.N)
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (which == 0) {
                        checkPermissionAndCamera();
                    } else if (which == 2) {
                        if (uploadMessageAboveL != null) {
                            uploadMessageAboveL.onReceiveValue(null);
                            uploadMessageAboveL = null;
                        }
                        if (uploadMessage != null) {
                            uploadMessage .onReceiveValue(null);
                            uploadMessage = null;
                        }
                        builder.create().dismiss();
                    } else {
                        Intent intent = new Intent(Intent.ACTION_PICK);
                        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                        startActivityForResult(intent, ACTION_CHOOSE_IMAGE);
                    }
                    return;
                }
            });//设置对话框 标题
            builder.create()
                    .show();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
     @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            Log.e("TAG", "resultCode:==="+resultCode);
            if (resultCode != RESULT_OK) {
                //取消拍照或者图片选择时,返回null,否则 再次点击无效果就是没有反应
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL.onReceiveValue(null);
                    uploadMessageAboveL = null;
    
                }
                if (uploadMessage != null) {
                    uploadMessage .onReceiveValue(null);
                    uploadMessage = null;
                 }
            }
            //相机返回
            if (requestCode == CAMERA_REQUEST_CODE) {
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL.onReceiveValue(new Uri[]{mCameraUri});
                    uploadMessageAboveL = null;
                }
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(mCameraUri);
                    uploadMessage = null;
                }
            }
             //相册返回
            if (requestCode == ACTION_CHOOSE_IMAGE) {
                if (data == null || data.getData() == null) {
                    if (uploadMessageAboveL != null) {
                        uploadMessageAboveL.onReceiveValue(null);
                        uploadMessageAboveL = null;
                    }
               	   if (uploadMessage != null) {
                  	  uploadMessage .onReceiveValue(null);
                  	  uploadMessage = null;
                	 }
                    return;
                }
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL.onReceiveValue(new Uri[]{data.getData()});
                    uploadMessageAboveL = null;
                }
                if (uploadMessage!= null) {
                    uploadMessage.onReceiveValue(data.getData());
                    uploadMessage= null;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    Zookeeper leader选举源码分析(超详细)
    pytorch 训练时raise EOFError EOFError
    引用
    虚拟机下载与Ubuntu安装
    【Spring】spring中存储Bean(对象)的相关注解及相关用法
    时隔一年的测评:gpt3.5发展到什么程度了?
    Cesium Vue(二)— 基础配置
    [C++] C/C++内存管理、
    网络信息安全岗位NISP应该如何面试(三)NISP管理中心
    设计模式截图记录
  • 原文地址:https://blog.csdn.net/afufufufu/article/details/127614048