课程名称: 2小时搞定移动端混合开发基础入门
课程章节: 课程全集
主讲老师: whinc
课程内容:
今天学习的内容包括:
JSBridge 实现原理;
JSBridge 实现方式:
- 拦截 URL Schema
- 注入 JS API
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 src="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();
}
}
}