Android接入WebView(一)——基本用法
Android接入WebView(二)——与JavaScript交互
Android接入WebView(三)——浏览器书签与历史记录与二维码分享
Android接入WebView(四)——浏览器书签与历史记录详细处理
Android接入WebView(五)——浏览器制作总结及源码分享
最近写了一个基于webview和zxing,sqlite实现的一款浏览器
主要功能有:扫描二维码以及打开本地二维码加载网页,书签和历史记录管理,无痕浏览,分享网址,分享网址二维码,浏览器出错自定义等功能。
源码地址:此资源解压后用Android可直接打开
制作浏览器书签与历史记录
我的思路是在本地创建一个sqlite用于保存书签与历史记录(关于sqlite的使用可以参考我的这篇文章)
如下:
首先创建一个MyDatabaseHelper类
package mountain_hua.browser;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by dhs on 2018/7/26.
*/
public class MyDatabaseHelper extends SQLiteOpenHelper {
//书签表
public static final String CREATE_bookmarkDB = "create table bookmarkDB(" +
"id integer primary key autoincrement," +
"title text key," +
"url text)";
//历史记录表
public static final String CREATE_historyDB = "create table historyDB(" +
"id integer primary key autoincrement," +
"title text key," +
"url text)";
private Context mContext;
//构造方法:
// 第一个参数Context上下文,
// 第二个参数数据库名,
// 第三个参数cursor允许我们在查询数据的时候返回一个自定义的光标位置,一般传入的都是null,
// 第四个参数表示目前库的版本号(用于对库进行升级)
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory , int version){
super(context,name ,factory,version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
//调用SQLiteDatabase中的execSQL()执行建表语句。
db.execSQL(CREATE_bookmarkDB);
db.execSQL(CREATE_historyDB);
//创建成功
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//更新表
db.execSQL("drop table if exists bookmarkDB");
db.execSQL("drop table if exists historyDB");
onCreate(db);
}
}
1.添加书签:
获取当前的网址的title和url,添加进数据库,为了用户体验,增加了对话框确认网址信息,如下:
//数据库添加数据(书签表)
public void addinfo(String title,String url){
//第二个参数是数据库名
dbHelper = new MyDatabaseHelper(MainActivity.this,"usersDataBase",null,1);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("title", title);
values.put("url", url);
//insert()方法中第一个参数是表名,第二个参数是表示给表中未指定数据的自动赋值为NULL。第三个参数是一个ContentValues对象
db.insert("bookmarkDB",null,values);
Toast.makeText(this,"添加成功",Toast.LENGTH_SHORT).show();
}
//添加书签对话框
//url详细信息对话框
public void url_infomation(){
final Dialog dialog = new Dialog(this, R.style.NormalDialogStyle);
View view = View.inflate(this, R.layout.bookmark_url_infomation, null);
text_title = (EditText) view.findViewById(R.id.editText2);
text_url = (EditText) view.findViewById(R.id.editText4);
sure=(Button)view.findViewById(R.id.button4);
dialog.setContentView(view);
//使得点击对话框外部可消失对话框
dialog.setCanceledOnTouchOutside(true);
//设置对话框的大小
view.setMinimumHeight((int) (ScreenSizeUtils.getInstance(this).getScreenHeight() * 0.23f));
Window dialogWindow = dialog.getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = (int) (ScreenSizeUtils.getInstance(this).getScreenWidth() * 0.75f);
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.CENTER;
dialogWindow.setAttributes(lp);
//显示详细信息
text_url.setText(webView.getUrl().toString());
text_title.setText(webView.getTitle().toString());
dialog.show();
//确定修改
sure.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addinfo(text_title.getText().toString(),text_url.getText().toString());
dialog.dismiss();
}
});
}
效果如下: 确认添加————————————————查看书签
现在需要打开书签返回url数据,用的是startActivityForResult()方法.
在MainActivity的打开书签按钮中:
Intent intent1=new Intent();
intent1.setClass(MainActivity.this,bookmark.class);
startActivityForResult(intent1,1);
MainActivity 的信息返回处理:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case 1:
//接收书签返回url
if(resultCode==RESULT_OK){
String dataStringExtra2= data.getStringExtra("2_data_return");
webView.loadUrl(dataStringExtra2);
}
case 2:
//接收历史记录返回url
if(resultCode==RESULT_OK){
String dataStringExtra2= data.getStringExtra("2_data_return");
webView.loadUrl(dataStringExtra2);
}
case 3:
//接收扫描二维码返回url
if(resultCode==RESULT_OK){
String dataStringExtra2= data.getStringExtra("2_data_return");
webView.loadUrl(dataStringExtra2);
}
}
}
在bookmark Activity中获得url后的处理:
即结束当前activity,并返回url
Intent mIntent = new Intent();//没有任何参数(意图),只是用来传递数据
mIntent.putExtra("2_data_return", url);
setResult(RESULT_OK, mIntent);
finish();
2.添加历史记录:
需要用这两个方法获取历史记录url和title
webView.copyBackForwardList().getCurrentItem().getTitle()
webView.copyBackForwardList().getCurrentItem().getUrl()
添加进数据库:
//数据库添加数据(历史记录表)
public void addinfo_history( String title,String url){
//第二个参数是数据库名
dbHelper = new MyDatabaseHelper(this,"usersDataBase",null,1);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("title", title);
values.put("url", url);
//insert()方法中第一个参数是表名,第二个参数是表示给表中未指定数据的自动赋值为NULL。第三个参数是一个ContentValues对象
db.insert("historyDB",null,values);
}
然后在setWebViewClient里面的 onPageFinished()方法里面执行把历史记录添加进数据库,但要在
shouldOverrideUrlLoading(),onPageStarted(),onPageFinished()这几个方法里设置一个boollean的变量if_load.
避免重定位导致的重复加载,给数据库里面添加两次历史记录
webView.setWebViewClient(new WebViewClient(){
boolean if_load;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if_load=false;
}
//页面完成即加入历史记录
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if(if_load&&!un_footprint) {
addinfo_history(view.copyBackForwardList().getCurrentItem().getTitle(), view.copyBackForwardList().getCurrentItem().getUrl());
if_load=false;
}
}
//页面开始
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon){
super.onPageStarted(view, url, favicon);
if_load=true;
}
});
然后在在MainActivity的打开历史记录按钮中调用startActivityForResult()方法,和书签按钮一样,此处不再赘述
另外我接入了二维码扫描网址与二维码分享的功能,有关zxing二维码的知识可以参考我的这两篇文章
(1)Android利用zxing生成二维码,识别二维码,中间填充图片超详细、超简易教程
(2)Android利用zxing用相机扫描识别二维码(添加闪光灯和本地二维码)超详细教程
接下来说说二维码分享
原理就是传入url,转化成二维码,再通过截屏分享,代码如下:
package mountain_hua.browser;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.Handler;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
/**
* Created by dhs on 2018/7/25.
*/
public class be_qrcode extends AppCompatActivity {
private ImageView im1; //imageview图片
private int w,h; //图片宽度w,高度h
private ProgressDialog dlog;//对话框
String filePath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.be_qrcode);
final String url=getIntent().getStringExtra("url");
final String title=getIntent().getStringExtra("title");
TextView textView=(TextView)findViewById(R.id.textView);
textView.setText(title);
//显示对话框,绘制二维码
dodialog(url);
Button bt=(Button)findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popShotSrceenDialog(url);
}
});
//返回上一页
Button bt2=(Button)findViewById(R.id.button2);
bt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
//转化为二维码:
public void createQRcodeImage(String url)
{
im1=(ImageView)findViewById(R.id.imageView1);
w=300;
h=300;
try
{
//判断URL合法性
if (url == null || "".equals(url) || url.length() < 1)
{
return;
}
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, w, h, hints);
int[] pixels = new int[w * h];
//下面这里按照二维码的算法,逐个生成二维码的图片,
//两个for循环是图片横列扫描的结果
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
if (bitMatrix.get(x, y))
{
pixels[y * w + x] = 0xff000000;
}
else
{
pixels[y * w + x] = 0xffffffff;
}
}
}
//生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
//显示到我们的ImageView上面
im1.setImageBitmap(bitmap);
}
catch (WriterException e)
{
e.printStackTrace();
}
}
//进度条对话框
private void dodialog(final String url){
dlog=ProgressDialog.show(be_qrcode.this,"正在生成二维码","请稍等。。。");
new Thread(){
@Override
public void run(){
super.run();
try {
createQRcodeImage(url);
} catch (Exception e) {
e.printStackTrace();
}
Message message=Message.obtain();
message.arg1=0;
message.what=2;
myHandler.sendMessage(message);
}
}.start();
}
//Handler
Handler myHandler = new Handler(){
/**
* handleMessage接收消息后进行相应的处理
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==2){
//使对话框消失
//Toast.makeText(be_qrcode.this,"二维码生成成功",Toast.LENGTH_SHORT).show();
dlog.dismiss();
}
}
};
//截屏功能
private void popShotSrceenDialog(String url){
final AlertDialog cutDialog = new AlertDialog.Builder(this).create();
View dialogView = View.inflate(this, R.layout.show_cut_screen_layout, null);
ImageView showImg = (ImageView) dialogView.findViewById(R.id.show_cut_screen_img);
dialogView.findViewById(R.id.share_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cutDialog.dismiss();
}
});
dialogView.findViewById(R.id.share_img).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//分享
Uri pa=Uri.fromFile(new File(filePath));//根据路径转化为uri
Intent imageIntent = new Intent(Intent.ACTION_SEND);//调用系统的ACTION_SEND
imageIntent.setType("image/png");
imageIntent.putExtra(Intent.EXTRA_STREAM, pa);//EXTRA_STREAM对应转化为uri的path
startActivity(Intent.createChooser(imageIntent, "分享"));
}
});
//获取当前屏幕的大小
int width = getWindow().getDecorView().getRootView().getWidth();
int height = getWindow().getDecorView().getRootView().getHeight();
//生成相同大小的图片
Bitmap temBitmap = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
//找到当前页面的跟布局
View view = getWindow().getDecorView().getRootView();
//设置缓存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//从缓存中获取当前屏幕的图片
temBitmap = view.getDrawingCache();
//保存图片
if (temBitmap != null)
{
try {
// 获取内置SD卡路径
String sdCardPath = Environment.getExternalStorageDirectory().getPath();
// 图片文件路径,获取系统时间
long time=System.currentTimeMillis();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
java.util.Date date=new java.util.Date(time);
String str=sdf.format(date);
filePath = sdCardPath + File.separator +str+"screenshot.png";
File file = new File(filePath);
FileOutputStream os = new FileOutputStream(file);
temBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
os.flush();
os.close();
} catch (Exception e) {
Toast.makeText(be_qrcode.this,"保存失败",Toast.LENGTH_SHORT).show();
}
}
showImg.setImageBitmap(temBitmap);
cutDialog.setView(dialogView);
Window window = cutDialog.getWindow();
window.setBackgroundDrawableResource(android.R.color.transparent);
WindowManager m = window.getWindowManager();
Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用
WindowManager.LayoutParams p = window.getAttributes(); // 获取对话框当前的参数值
p.height = (int) (d.getHeight() * 0.8); // 高度设置为屏幕的0.6
p.gravity = Gravity.CENTER;//设置弹出框位置
window.setAttributes(p);
window.setWindowAnimations(R.style.dialogWindowAnim);
cutDialog.show();
}
}