第一个WebView程序:加载远程网址
Layout添加WebView组件;
初始化组件,加载Url;
public class FirstWebViewActivity extends AppCompatActivity{
private WebView webView_first;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_web_view);
webView_first=findViewById(R.id.webView_first);
webView_first.loadUrl("https://www.baidu.com/");
}
@Override
protected void onDestroy() {
super.onDestroy();
webView_first.removeAllViews();
webView_first.destroy();
}
}
Manifest文件添加网络访问权限
<uses-permission android:name="android.permission.INTERNET" />
出现错误:
NetworkSecurityConfig com.hymy.webviewstarter D No Network Security Config specified, using platform default
Denied starting an intent without a user gesture, URI
解决方法:
res/xml下添加 network_security_config.xml 文件:
<network-security-config> //默认配置:允许明文通信
<base-config cleartextTrafficPermitted="true" />
network-security-config>
在AndroidManifest.xml中引用
出现错误:
访问bing.com无法加载封面图片:
The resource xxx was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.
解决方法:
webView_first=findViewById(R.id.webView_first);
//启用JavaScript
WebSettings webSettings = webView_first.getSettings();
webSettings.setJavaScriptEnabled(true);
webView_first.loadUrl("https://cn.bing.com/?mkt=zh-CN");
下载:在bing搜索网站首页,好看的壁纸,点击可以下载图片,将图片下载到 SD 卡下的Downloader目录下
参考:https://cloud.tencent.com/developer/article/1742327
将 JavaScript代码绑定到Android代码
js调用Android代码中的方法
新建 WebAppInterface 类
/**
* @Author : alex
* @Date : on 2023/11/14 09:21.
* @Description :描述
*/
public class WebAppInterface {
Context mContext;
/**
* 初始化接口,并设置context
* @param c
*/
WebAppInterface(Context c){
mContext=c;
}
/**
* 在Web页面显示消息提示
* @param toast
*/
@JavascriptInterface
public void showToast(String toast){
Toast.makeText(mContext,toast,Toast.LENGTH_SHORT).show();
}
}
webview 绑定接口:
webView_first.addJavascriptInterface(new WebAppInterface(this),"Android");
html代码示例:
Bootstrap demo
Hello, world!
webview中的跳转连接
参考:https://www.digitalocean.com/community/tutorials/android-webview-example-tutorial
当 html 中有跳转链接的时候,可以直接阻止、选择性阻止在我们的App跳转、或者可以打开系统浏览器,加载外部链接。
webView_first.setWebViewClient(new MyWebViewClient());
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.i("FirstWebViewActivity",request.getUrl().getHost());
if ("192.168.96.108".equals(request.getUrl().getHost())) {
// This is my website, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
startActivity(intent);
return true;
}
}
webview加载本地网页,实现 sqlite 数据库增删改查
使用的库 gson:
implementation 'com.google.code.gson:gson:2.8.5'
首先新建assets文件夹,android默认工程没有创建。
编写 DBHelper ,定义数据库名,在 onCreate 中初始化数据库:
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "student.db";
public static final int DATABASE_VERSION =1;
public MyDatabaseHelper(Context context){
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 数据库首次创建时调用,执行创建表等语句
// 创建student表
db.execSQL("CREATE TABLE student (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT," +
"age INTEGER," +
"birth TEXT)");
// 如果需要初始化数据可以在这里插入:
db.execSQL("INSERT INTO student (name, age, birth) " +
"VALUES ('张三', 18, '1980-01-01')");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 数据库版本更新时调用
}
}
然后定义 MyApplication,在程序启动的时候初始化数据库:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//检测数据库是否存在,不存在则创建数据库
Context context = getApplicationContext();
MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
}
}
定义数据增、查接口类,供H5中调用:
public class JsDBInterface {
private SQLiteDatabase db;
public JsDBInterface(Context context){
// 在构造函数中打开数据库
MyDatabaseHelper helper = new MyDatabaseHelper(context);
db = helper.getWritableDatabase();
}
/**
* 插入数据
* @param name
* @param age
* @param birth
*/
@JavascriptInterface
public void insertData(String name,int age,String birth){
//检查参数
if(name==null||name.isEmpty()){
return;
}
//插入数据
ContentValues values = new ContentValues();
values.put("name",name);
values.put("age",age);
values.put("birth",birth);
db.insert("student",null,values);
Log.i("插入数据",name);
}
/**
* 查询数据
* @return
*/
@JavascriptInterface
public String getAllStudents(){
List<Student> students = new ArrayList<>();
//查询数据库中的所有学生
Cursor cursor = db.query("student",null,null,null,null,null,null);
//获取所有列
// String[] cols = cursor.getColumnNames();
// int nameIndex=-1;
while (cursor.moveToNext()){
int columnIndex1=cursor.getColumnIndex("id");
int columnIndex2=cursor.getColumnIndex("name");
int columnIndex3=cursor.getColumnIndex("age");
int columnIndex4=cursor.getColumnIndex("birth");
int id=0;String name="null";int age=0;String birth="0000-00-00";
if(columnIndex1>=0){
id = cursor.getInt(columnIndex1);
}
if(columnIndex2>=0){
name=cursor.getString(columnIndex2);
}
if(columnIndex3>=0){
age = cursor.getInt(columnIndex3);
}
if(columnIndex4>=0){
birth=cursor.getString(columnIndex4);
}
Student stu = new Student(id,name,age,birth);
students.add(stu);
}
cursor.close();
Gson gson = new Gson();
String json = gson.toJson(students);
return json;
}
}
数据实体类:
public class Student {
private int id;
private String name;
private int age;
private String birth;
public int getId() {
return id;
}
public Student(int id,String name, int age, String birth) {
this.id=id;
this.name = name;
this.age = age;
this.birth = birth;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getBirth() {
return birth;
}
public void setBirth(String birth) {
this.birth = birth;
}
}
在 Activity 中注册接口:
webView.addJavascriptInterface(new JsDBInterface(MainActivity.this),"JsDBInterface");
加载本地网页:
private String localUrl="file:///android_asset/index.html";
webView_first.loadUrl(localUrl);
HTML 使用了vue,调用代码如下:
Document
{{message}}
- {{user.name}}
webview h5 alert 不运行
参考:https://copyprogramming.com/howto/modify-alert-title-javascript-in-android-webview
最简单的处理方法是:添加下面的代码
webView_first.setWebChromeClient(new WebChromeClient());
但是上面的标题会显示网址,可以用下面的方法进行修改:
webView_first.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
AlertDialog dialog = new AlertDialog.Builder(view.getContext())
.setTitle("提示")
.setMessage(message)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
}).create();
dialog.show();
result.confirm();
return true;
}
});
修改后:
此外如果对 alert, prompt, confirm统一进行修改,可以使用下面代码:
webView_first.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
new AlertDialog.Builder(view.getContext())
.setTitle("alert")
.setMessage(message)
.setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm())
.setOnDismissListener((DialogInterface dialog) -> result.confirm())
.create()
.show();
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
new AlertDialog.Builder(view.getContext())
.setTitle("confirm")
.setMessage(message)
.setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm())
.setNegativeButton("取消", (DialogInterface dialog, int which) -> result.cancel())
.setOnDismissListener((DialogInterface dialog) -> result.cancel())
.create()
.show();
return true;
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
final EditText input = new EditText(view.getContext());
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(defaultValue);
new AlertDialog.Builder(view.getContext())
.setTitle("prompt")
.setMessage(message)
.setView(input)
.setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm(input.getText().toString()))
.setNegativeButton("取消", (DialogInterface dialog, int which) -> result.cancel())
.setOnDismissListener((DialogInterface dialog) -> result.cancel())
.create()
.show();
return true;
}
});