一、H5链接打开App

点击浏览器中的URL,如何启动App呢?

1、HTML链接处理

首先做成HTML的内容,url格式如下:


<a href="[scheme]://[host]/[path]?[query]">启动应用程序</a>


说明 :

schema: 判断启动的App

host: 标记

path: 标记,可无

query:  传值的(key,value)键值对,可无

例如:


<a href="myapp://jp.app/openwith?name=zhangsan&age=26">启动应用程序</a>

本例中做如下超链接跳转:


<a href="finance://pay.com/mpos?orderId=1020160126"> Open APP </a>

其中:

   schema  ----  finance   对应android中 android:schema

全部Html源码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>mpos</title>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0">
<meta name="imagemode" content="force">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
</head>
<body>
<h1>H5打开APP</h1>
<a href="finance://pay.com/mpos?orderId=102016000"> Open APP </a>
</body>
</html>

2、android中如何处理?

1)在AndroidManifest.xml文件中,在需要跳转到的Activity中添加如下声明:

<activity
            android:name=".ui.activity.OrderDetailActivity"
            android:configChanges="keyboardHidden|orientation"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/CustomTitle">

            <intent-filter>
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.intent.action.VIEW" />
                <data
                    android:host="pay.com"
                    android:pathPrefix="/mpos"
                    android:scheme="finance" />
            </intent-filter>
        </activity>



2)如何获取链接中传递的数据?

if (getIntent() != null) {
	if (Intent.ACTION_VIEW.equals(action)) {
              	Uri uri = Uri.parse(getIntent().getDataString());
              	if (uri != null) {
			String orderId = uri.getQueryParameter("orderId");
		}
	}
 }


3 、应该注意的地方?

1)链接打开的Activity中,【android.intent.action.MAIN】和【android.intent.category.LAUNCHER】这2个,不能与这次追加的内容混合在一起;如果跳转的刚好是启动Activity,可以写一个类继承启动类。

2)参考:

二、App打开H5

使用WebView加载,传值可参考框架JsBridgeWebView。

GitHub地址:https://github.com/lzyzsd/JsBridge

加载远程html:webView.loadUrl("http://www.baidu.com");

加载本地html:webView.loadUrl("file:///android_asset/web_app.html");

三、App打开App

例如,点击app1某个页面中的按钮,要打开app2,

1、先检测是否安装了app2,客人通过包名检测;

2、安装,例如打开微信,如果没有安装就跳转到下载页:


try {
			PackageManager packageManager = getPackageManager(); 
			Intent intent=new Intent(); 
			intent = packageManager.getLaunchIntentForPackage("com.tencent.mm");
			startActivity(intent);
		} catch (Exception e) {
			e.printStackTrace();
			Intent viewIntent = new
			Intent("android.intent.action.VIEW",Uri.parse("http://weixin.qq.com/"));
			startActivity(viewIntent);
}

或者

Intent intent = new Intent(Intent.ACTION_MAIN);
		intent.addCategory(Intent.CATEGORY_LAUNCHER);            
		ComponentName cn = new ComponentName(app2PackageName, className);            
		intent.setComponent(cn);
		startActivity(intent);

3、如何从.aar中的某个页面跳转到主项目的某个页面?

使用隐式Intent跳转,具体如下:

1)主项目中:

<activity
            android:name="com.ddqb.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.ddqb.MainActivity"/>
                <category android:name="android.intent.category.DEFAULT" />  <!--要设置一下category-->
            </intent-filter>
        </activity>
findViewById(R.id.enter_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(LoginTestAcitvity.this, TestActivity.class);  // TestActivity为.aar依赖库中的页面
                startActivity(intent);

            }
        });

2).aar项目中:

findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.ddqb.MainActivity");
                intent.addCategory("android.intent.category.DEFAULT");
                TestActivity.this.startActivity(intent);
            }
        });

四、H5与App交互

1、WebView基础设置如下:

String mUrl = "http://10.0.41.19:8099/TomcatTest/web_app_upload_image.html";
        WebSettings webSettings = webView.getSettings();
        //设置WebView属性,能够执行Javascript脚本
        webSettings.setJavaScriptEnabled(true);
        //设置可以访问文件
        webSettings.setAllowFileAccess(true);
        //设置支持缩放
        webSettings.setBuiltInZoomControls(true);
        //加载需要显示的网页
        // 加载 asset目录下的本地html文件: mUrl = "file:///android_asset/web_app.html"
        webView.loadUrl(mUrl);
        //设置WebViewClient用来辅助WebView处理各种通知请求事件等,如更新历史记录、网页开始加载/完毕、报告错误信息等
        webView.setWebViewClient(new WebViewClient() {

            // 以下方法避免 自动打开系统自带的浏览器,而是让新打开的网页在当前的WebView中显示
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });

        // 用于辅助WebView处理JavaScript的对话框、网站图标、网站标题以及网页加载进度等
        webView.setWebChromeClient(new WebChromeClient() {

            @Override
            public void onReceivedTitle(WebView view, String title) {
                tv_title.setText(title);
            }
        });
        // 使 H5可调用Native方法: android.nativeMethod()
        webView.addJavascriptInterface(new MyJsInterface(), "android");

2、H5 调用 Native 方法实现 H5页面 按钮点击事件处理,代码如下:

<input type="button" value="JS Call Native: Toast Message" οnclick="android.toastMessage()">

     App WebViewActivity类中处理:

public class MyJsInterface {

        @JavascriptInterface
        public void toastMessage(String msg) {
            Toast.makeText(WebViewActivity.this, "app to H5 toast " + msg, Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(WebViewActivity.this, FirstActivity.class);
            WebViewActivity.this.startActivity(intent);
        }

3、Native 传递数据给 H5,场景:点击原生页面的标题栏按钮,给H5页面传值 并且更新 H5页面:

// 点击原生按钮,向H5页面发送数据,可更新H5页面
        tv_click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msg = "from Native";
                // loadUrl必须在主线程中执行
                webView.loadUrl("javascript:toNative('" + msg + "')");
            }
        });

     H5 中页面数据更新代码:

<input type="text" value="hhhh" id="pp"/>
 
<script type="text/javascript"> 
	// 2. js供 Native 调用的方法
	function toNative(msg) {
		alert("Hello, from H5, received msg: " + msg);
		var p = document.getElementById("pp");
		p.value = msg;
	}
</script>

五、H5页面从App图库中选择图片并在H5页面显示所选图片:

步骤一:重写onShowFileChooser / openFileChooser 方法(还要兼容其他各个版本)

private static final int REQUEST_LOAD_IMAGE_FROM_GALLERY = 0x10;
    private ValueCallback<Uri> mSingleFileCallback;
    private ValueCallback<Uri[]> mMultiFileCallback;
    private Uri imageUri;
    private void setWebChromeClient() {
        webView.setWebChromeClient(new WebChromeClient() {

            @Override
            public void onReceivedTitle(WebView view, String title) {
                tv_title.setText(title);
            }

            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                Log.e("Webview", "onShowFileChooser");
                mMultiFileCallback = filePathCallback;
                openGallery();

                return true;  // 一定要return true 防止下次回到 WebView页面重新调用,抛异常 duplicate result
            }

            // 5.0以下的文件上传监听方法
            public void openFileChooser(ValueCallback<Uri> uploadMsg) {
                Log.e("Webview", "openFileChooser");
                mSingleFileCallback = uploadMsg;
                openGallery();
            }
        });
    }

    private void openGallery() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
        intent.setType("image/*");
        startActivityForResult(intent, REQUEST_LOAD_IMAGE_FROM_GALLERY);
    }

步骤二:在onActivityResult 中获取所选图片 uri,回调给 H5(目前代码有点小缺陷,图片需要压缩,因为在H5加载 base64本地图片是耗时操作,要先压缩图片);

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_LOAD_IMAGE_FROM_GALLERY) {
            if (mSingleFileCallback == null && mMultiFileCallback == null) {
                return;
            }
            Uri tempUri = null;
            if (data != null) {
                String url = CommonUtil.getPath(WebViewActivity.this, data.getData());
                File temp = new File(url);
                tempUri = Uri.fromFile(temp);
            }

            if (mSingleFileCallback != null) { // 5.0以下处理方式
                if (data != null) {
                    mSingleFileCallback.onReceiveValue(tempUri);
                } else {
                    mSingleFileCallback.onReceiveValue(imageUri);
                }
                mSingleFileCallback = null;
            } else if (mMultiFileCallback != null) { // 5.0版本以上
                Uri[] uris = null;
                if (data == null) {
                    uris = new Uri[] {imageUri};
                } else {
                    // 多选图片[图片一定要压缩,转化为base网页加载很慢]
                    String dataString = data.getDataString();
                    ClipData clipData = data.getClipData();
                    if (clipData != null) {
                        int size = clipData.getItemCount();
                        uris = new Uri[size];
                        for (int i = 0; i < size; i++) {
                            // 将所选图片的 url保存到 uris数组中
                            uris[i] = clipData.getItemAt(i).getUri();
                        }
                    }
                    if (!TextUtils.isEmpty(dataString)) {
                        uris = new Uri[] {Uri.parse(dataString)};
                    }
                }

                if (uris == null) {
                    mMultiFileCallback.onReceiveValue(null);
                    mMultiFileCallback = null;
                } else {
                    mMultiFileCallback.onReceiveValue(uris);
                    mMultiFileCallback = null;
                }
            }
        }
    }

步骤三:在html页面中,使用 FileReader 获取上传的图片base64编码并显示在img标签:

<input accept="image/*" capture="camera" id="imgFile" name="imgFile"  type="file"  οnchange="previewFile()" > <br/>
 <p></p>
 <img src="" id="img" />
function previewFile() {
		var img = document.getElementById("img");
		// 仅限上传单张图片
	    var file = document.querySelector('input[type=file]').files[0];
	    
	    var reader  = new FileReader();	    	    
		reader.addEventListener("load", function () {
			    img.src = reader.result;  // 存储在本地的图片的base64编码
			    alert("result=" + reader.result);
	    }, false);

	    if (file) {
	      reader.readAsDataURL(file);
	    }
	 }