课程名称: 2小时搞定移动端混合开发基础入门
课程章节: 课程全集
主讲老师: whinc
今天学习的内容包括:
JSBridge 实现原理;
JSBridge 实现方式:
Web 端如何发送原生 HTTP 请求
问题:webView.evaluateJavascript报错:webView.evaluateJavascript(jsCode, resultCallback:null);
回答:resultCallback:不要填写
问题:Chrome如何调试Android WebView
回答:第一次打开 DevTools 需要访问 Google Chrome 下载设备相关文件
课程实例:
/jsbridge-principle/web/index.html
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> * { font-size: 50px; } </style> <script> window.showWebDialog = text => window.alert(text); document.addEventListener('DOMContentLoaded', e => { const editText = document.querySelector('#editText'); const showBtn = document.querySelector('#showBtn'); showBtn.addEventListener('click', e => { const inputValue = editText.value; showNativeDialog(inputValue) }) }) function showNativeDialog (text) { // window.alert('jsbridge://showNativeDialog?text=' + text); window.NativeBridge.showNativeDialog(text); } </script> </head> <body> <div> <input id="editText" type="text" placeholder="输入内容" /> </div> <div> <button id="showBtn">显示Native弹窗</button> </div> </body> </html>
/jsbridge-principle/native/app/src/main/java/com/example/jsbridge/MainActivity.java
package com.example.jsbridge; import androidx.appcompat.app.AppCompatActivity; import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; import android.view.View; import android.webkit.JavascriptInterface; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.widget.Button; import android.widget.EditText; import java.util.Date; public class MainActivity extends AppCompatActivity { private WebView webView; private EditText editText; private Button showBtn; private Button refreshBtn; private MainActivity self = this; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.webView); editText = findViewById(R.id.editText); showBtn = findViewById(R.id.showBtn); refreshBtn = findViewById(R.id.refreshBtn); webView.loadUrl("http://10.43.101.59:18929?timestamp=" + new Date().getTime()); webView.getSettings().setJavaScriptEnabled(true); webView.setWebChromeClient(new WebChromeClient()); webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge"); showBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String inputValue = editText.getText().toString(); self.showWebDialog(inputValue); } }); refreshBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { webView.loadUrl("http://10.43.101.59:18929?timestamp=" + new Date().getTime()); } }); } private void showWebDialog (String text) { String jsCode = String.format("window.showWebDialog('%s')", text); webView.evaluateJavascript(jsCode, null); } // private void showNativeDialog(String text) { // new AlertDialog.Builder(this).setMessage(text).create().show(); // } class NativeBridge { private Context ctx; NativeBridge(Context ctx) { this.ctx = ctx; } @JavascriptInterface public void showNativeDialog(String text) { new AlertDialog.Builder(ctx).setMessage(text).create().show(); } } }
/hybrid-app/web/index.html
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo</title> <style> * { font-size: 50px; } </style> <script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://unpkg.com/dsbridge@3.1.3/dist/dsbridge.js"> </script> <script> document.addEventListener('DOMContentLoaded', e => { const urlTextEl = document.querySelector('#urlText') const sendBtn = document.querySelector('#sendBtn') const responseEl = document.querySelector('#response') sendBtn.addEventListener('click', e => { const url = urlTextEl.value if (url) { // 清除旧数据 responseEl.textContent = '' // 发送原生请求 dsBridge.call("nativeRequest", {url: url}, data => { responseEl.textContent = data }) } }) }) dsBridge.register("changeTheme", color => { // android 0xFFFF0000 ARGB // web 0xFF0000FF RGBA document.body.style.backgroundColor = '#' + (color & 0x00FFFFFF).toString(16) }) </script> </head> <body> <div> <input id="urlText" type="text" value="http://www.google.com" /> <button id="sendBtn">发送请求</button> </div> <div> <p>请求返回:</p> <p id="response"></p> </div> </body> </html>
/native/app/src/main/java/com/example/demo/MainActivity.java
package com.example.demo; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.WindowManager; import android.webkit.JavascriptInterface; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import wendu.dsbridge.CompletionHandler; import wendu.dsbridge.DWebView; public class MainActivity extends AppCompatActivity { private DWebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.webView); webView.addJavascriptObject(new JsApi(), null); webView.loadUrl("http://10.43.101.59:8080"); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { changeTheme(0xFFFF0000); return true; } // 换肤 private void changeTheme (int color) { // 状态栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); getWindow().setStatusBarColor(color); // 标题栏 getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color)); // 导航栏 getWindow().setNavigationBarColor(color); // Web 网页的背景 webView.callHandler("changeTheme", new Object[]{color}); } public class JsApi { @JavascriptInterface public void nativeRequest(Object params, CompletionHandler handler) { try { String url = ((JSONObject)params).getString("url"); String data = request(url); handler.complete(data); } catch (Exception e) { handler.complete(e.getMessage()); e.printStackTrace(); } } private String request(String urlSpec) throws Exception { HttpURLConnection connection = (HttpURLConnection) new URL(urlSpec).openConnection(); connection.setRequestMethod("GET"); InputStream inputStream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer result = new StringBuffer(); String line; while((line = reader.readLine()) != null) { result.append(line); } reader.close(); connection.disconnect(); return result.toString(); } } }