以前写过这样的文章-跳转查看,最近闲来无聊想回顾一下,发现居然没看懂…这是万万不可的,写博客的初衷都没到达,自己都看不懂,更别说分享给别人了,所以又重新写了一份,希望某日之后回顾的时候能够轻松想起此时的思路。
首先通过此文章你可以了解到:
1.原生与H5交互
2.如何通过WebView将网页引入到APP中
3.一像素保活法具体实战
为了充分去体会到原生与H5的交互过程,这里写了一个切换效果
上一个,下一个,展示属于原生范围,整体界面和切换背景是H5部分,点击展示之后返回手机原页面,并且手机能够正常使用(类似一像素保活用法),注:未手机适配,不同手机可能出现效果不同
首先需要两个html界面以及两个Activity,其中一个是操作Activity,另一个是左下角的Activity,左下角这个模仿一像素保活法,只不过将一像素改成对应大小,以及添加了layout。
首先创建 assets 文件夹,用于存放 html 文件
两个html文件内容如下:
live2D
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>live2d模型</title>
<style type="text/css">
.rgba{
background-color: rgba(0,0,0,1);
background-position: center 0;
background-size: cover;
min-height: 100vh;
}
</style>
</head>
<body class="rgba">
<input type="button" value="切换背景" onclick="jsColor() " />
</body>
<!-- 导入模型的脚本文件 -->
<script src="https://eqcn.ajz.miesnfu.com/wp-content/plugins/wp-3d-pony/live2dw/lib/L2Dwidget.min.js"></script>
<script language="javascript">
//人物集合
var arr = ["https://unpkg.com/live2d-widget-model-chitose@1.0.5/assets/chitose.model.json",
"https://unpkg.com/live2d-widget-model-haruto@1.0.5/assets/haruto.model.json",
"https://unpkg.com/live2d-widget-model-hibiki@1.0.5/assets/hibiki.model.json",
"https://unpkg.com/live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json",
"https://unpkg.com/live2d-widget-model-izumi@1.0.5/assets/izumi.model.json",
"https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json",
"https://unpkg.com/live2d-widget-model-miku@1.0.5/assets/miku.model.json",
"https://unpkg.com/live2d-widget-model-ni-j@1.0.5/assets/ni-j.model.json",
"https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json",
"https://unpkg.com/live2d-widget-model-tororo@1.0.5/assets/tororo.model.json",
"https://unpkg.com/live2d-widget-model-tsumiki@1.0.5/assets/tsumiki.model.json",
"https://unpkg.com/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json",
"https://unpkg.com/live2d-widget-model-z16@1.0.5/assets/z16.model.json",
"https://unpkg.com/live2d-widget-model-nico@1.0.5/assets/nico.model.json",
"https://unpkg.com/live2d-widget-model-nipsilon@1.0.5/assets/nipsilon.model.json",
"https://unpkg.com/live2d-widget-model-nito@1.0.5/assets/nito.model.json",
"https://unpkg.com/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json"];
//背景集合
var color = ["https://c-ssl.duitang.com/uploads/item/202007/01/20200701073201_dMUFs.thumb.1000_0.gif",
"http://img.bimg.126.net/photo/eqj93LhUGXGIJiJfOhQ4KA==/334110797356199467.jpg",
"http://p3.itc.cn/q_70/images03/20200916/1d4adfc4ac6f4e7ca08f3c563bafdd0b.gif",
"https://c-ssl.duitang.com/uploads/blog/202104/24/20210424120118_378cf.thumb.1000_0.gif",];
var i = 0; //默认人物下标
var j = 0; //默认背景下标
//设置背景
function jsColor(){
if(j >= color.length){
j = 0;
}
document.body.style.backgroundImage="URL("+color[j]+")";
test.getBjIndex(j)
j++;
}
//设置人物
function jsBack(){
if (i >0 ){
i--;
}else{
//调用原生方法
test.initJS();
}
setL2();
}
//设置人物
function jsNext(){
if (i < arr.length ){
i++;
}else{
//调用原生方法
test.initJS();
}
setL2();
}
//点击方法之后打开的
function setL2(){
test.getRwIndex(i)
L2Dwidget.init({
// 引用的模型
"model": {
jsonPath: arr[i], //设置人物
"scale": 1
},
// 模型的样式,可以自行更改
"display": {
"position": "right",
"width": 150,
"height": 350,
"hOffset": 50,
"vOffset": 50
},
"mobile": {
"show": true,
"scale": 1
},
"react": {
"opacityDefault": 1,
"opacityOnHover":2
}
});
}
//进来之后默认打开的人物
L2Dwidget.init({
// 引用的模型
"model": {
jsonPath: arr[i],
"scale": 1
},
// 模型的样式,可以自行更改
"display": {
"position": "right",
"width": 150,
"height": 350,
"hOffset": 50,
"vOffset": 50
},
"mobile": {
"show": true,
"scale": 1
},
"react": {
"opacityDefault": 1,
"opacityOnHover":2
}
});
</script>
</html>
live2D_title
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>live2d模型</title>
<style type="text/css">
.rgba{
background-color: rgba(0,0,0,1);
background-position: center 0;
background-size: cover;
min-height: 100vh;
}
</style>
</head>
<body class="rgba">
</body>
<!-- 导入模型的脚本文件 -->
<script src="https://eqcn.ajz.miesnfu.com/wp-content/plugins/wp-3d-pony/live2dw/lib/L2Dwidget.min.js"></script>
<script language="javascript">
//人物集合
var arr = ["https://unpkg.com/live2d-widget-model-chitose@1.0.5/assets/chitose.model.json",
"https://unpkg.com/live2d-widget-model-haruto@1.0.5/assets/haruto.model.json",
"https://unpkg.com/live2d-widget-model-hibiki@1.0.5/assets/hibiki.model.json",
"https://unpkg.com/live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json",
"https://unpkg.com/live2d-widget-model-izumi@1.0.5/assets/izumi.model.json",
"https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json",
"https://unpkg.com/live2d-widget-model-miku@1.0.5/assets/miku.model.json",
"https://unpkg.com/live2d-widget-model-ni-j@1.0.5/assets/ni-j.model.json",
"https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json",
"https://unpkg.com/live2d-widget-model-tororo@1.0.5/assets/tororo.model.json",
"https://unpkg.com/live2d-widget-model-tsumiki@1.0.5/assets/tsumiki.model.json",
"https://unpkg.com/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json",
"https://unpkg.com/live2d-widget-model-z16@1.0.5/assets/z16.model.json",
"https://unpkg.com/live2d-widget-model-nico@1.0.5/assets/nico.model.json",
"https://unpkg.com/live2d-widget-model-nipsilon@1.0.5/assets/nipsilon.model.json",
"https://unpkg.com/live2d-widget-model-nito@1.0.5/assets/nito.model.json",
"https://unpkg.com/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json"];
//背景集合
var color = ["https://c-ssl.duitang.com/uploads/item/202007/01/20200701073201_dMUFs.thumb.1000_0.gif",
"http://img.bimg.126.net/photo/eqj93LhUGXGIJiJfOhQ4KA==/334110797356199467.jpg",
"http://p3.itc.cn/q_70/images03/20200916/1d4adfc4ac6f4e7ca08f3c563bafdd0b.gif",
"https://c-ssl.duitang.com/uploads/blog/202104/24/20210424120118_378cf.thumb.1000_0.gif",];
//点击方法之后打开的
function setL2(i,j){
//设置背景
document.body.style.backgroundImage="URL("+color[i]+")";
//进来之后默认打开的人物
L2Dwidget.init({
// 引用的模型
"model": {
jsonPath: arr[j],
"scale": 1
},
// 模型的样式,可以自行更改
"display": {
"position": "left,bottom",
"width": 23,
"height": 60,
"hOffset": 0,
"vOffset": 0
},
"mobile": {
"show": true,
"scale": 1
},
"react": {
"opacityDefault": 1,
"opacityOnHover":2
}
});
}
</script>
</html>
其次在Activity将WebView与界面绑定
如何通过WebView将网页引入到APP中
-
其中
mDataBind.mWebView.loadUrl("file:///android_asset/live2D.html")
是添加html到WebView中,注意下路径 file:///android_asset/ 如果有其他子路径,类似写下去,android_asset 就是刚才建的存放html的文件夹 -
mDataBind.mWebView.addJavascriptInterface(this, "test")
此方法是将整个Activity与该界面的JS相关联,此后在该WebView对应的html中 test 就代表了该Activity,用于Js调用原生方法 -
别忘了设置该WebView支持JS,否则整体方法就无效了
原生与H5交互,以此代码具体介绍
1.原生调用H5(无参)
原生中
H5中
2.H5调用原生(无参)
原生中
别忘了添加注解,否则找不到对应的方法(Koltin写法与Java写法需注意)
@SuppressLint("JavascriptInterface")
@JavascriptInterface
H5中
这里的 test 是不是有点眼熟呢,这就是通过 addJavascriptInterface 方法设置的那个,直接拿来调用就可以了。
3.原生调用H5(有参)
原生中
可以看到与无参的区别就是在括号内添加了对应参数,如果是多个参数别忘了添加 逗号哦
H5中
可以看到 JS 参数直接定义就可以,然后直接拿来用,多个参数别忘了逗号哦。
4. H5调用原生方法(有参)
原生中
H5中
一像素保活法具体实战
这里为什么要说一下这个呢,本人感觉这部分比较有意思,毕竟也是有过辉煌历史的写法,通过最开始截图也可以看出整体Activity是一小块,以前的文章里也是一小块,不过是伪造的方式,整体APP是无法操作的,这次是可以操作的
核心代码部分
单独写过一像素的Demo,发现APP确实有一像素,但是手机无法进行其他操作,那肯定是不行的,通过不可触摸解决了一像素Activity下手机无法操作的问题
//全屏不可触摸
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
//取消全屏不可触摸
//window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
最后说一下整体思路:
- 在 html 中将不同的看娘资源和背景分别放在不同的集合里,通过原生调用H5方法进行切换
- 切换之后通过 H5 调用原生方法 将当前下标传给原生
- 原生拿到下标,点击展示的时候跳转的像素Activity并将下标传过去
- 像素Activity拿到下标,通过原生调用H5方法将 下标传给 H5 进行展示
全部代码贴出:
1.网络权限
<uses-permission android:name="android.permission.INTERNET" />
2.使用dataBinding
dataBinding {
enabled = true
}
3.整体目录
MainActivity
class MainActivity : AppCompatActivity() {
lateinit var mDataBind: ActivityMainBinding
var bjIndex = "0"
var rwIndex = "0"
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mDataBind = DataBindingUtil.setContentView(this,R.layout.activity_main)
initBar()
initWeb()
initEvent()
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun initBar(){
this.window.statusBarColor = this.resources.getColor(R.color.white)
this.window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
@SuppressLint("SetJavaScriptEnabled", "JavascriptInterface")
private fun initWeb(){
mDataBind.mWebView.webChromeClient = WebChromeClient()
mDataBind.mWebView.settings.javaScriptEnabled = true
mDataBind.mWebView.settings.domStorageEnabled = true
mDataBind.mWebView.settings.javaScriptCanOpenWindowsAutomatically = true
//mDataBind.mWebView.setBackgroundColor(0);//设置背景色
//mDataBind.mWebView.background.alpha = 0;//设置填充透明度(布局中一定要设置background,不然getbackground会是null)
mDataBind.mWebView.addJavascriptInterface(this, "test")
mDataBind.mWebView.loadUrl("file:///android_asset/live2D.html")
}
private fun initEvent(){
mDataBind.tvBack.setOnClickListener {
mDataBind.mWebView.loadUrl("javascript:jsBack()");
}
mDataBind.tvNext.setOnClickListener {
mDataBind.mWebView.loadUrl("javascript:jsNext()");
}
mDataBind.tvSelect.setOnClickListener {
val it = Intent(this@MainActivity, ShowActivity::class.java)
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
it.putExtra("BJ_KEY",bjIndex)
it.putExtra("RW_KEY",rwIndex)
startActivity(it)
finish()
}
}
@SuppressLint("JavascriptInterface")
@JavascriptInterface
fun initWVBack(){
Toast.makeText(this,"设置背景",Toast.LENGTH_SHORT).show()
}
@SuppressLint("JavascriptInterface")
@JavascriptInterface
fun initJS(){
Toast.makeText(this,"没了..",Toast.LENGTH_SHORT).show()
}
@SuppressLint("JavascriptInterface")
@JavascriptInterface
fun getBjIndex(s: String){
this.bjIndex = s
}
@SuppressLint("JavascriptInterface")
@JavascriptInterface
fun getRwIndex(s: String){
this.rwIndex = s
}
}
ShowActivity
class ShowActivity : AppCompatActivity() {
lateinit var mDataBind: ActivityShowBinding
var bjKey = "BJ_KEY"
var rwKey = "RW_KEY"
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//一像素的时候不需要setContentView方法
mDataBind = DataBindingUtil.setContentView(this,R.layout.activity_show);
val window = window
//一像素保护法通用默认是左上
window.setGravity(Gravity.LEFT or Gravity.BOTTOM)
val params = window.attributes
params.x = 0
params.y = 0
//一像素的时候这里都是1
params.height = 400
params.width = 200
window.attributes = params
// @SuppressLint("UseCompatLoadingForDrawables") val drawable =
// this.resources.getDrawable(R.drawable.ic_launcher_background)
// window.setBackgroundDrawable(drawable)
//全屏不可触摸
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
//取消全屏不可触摸
//window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
//获取数据
val i = intent.getStringExtra(bjKey)
val j = intent.getStringExtra(rwKey)
initWeb(i,j)
}
@SuppressLint("JavascriptInterface")
private fun initWeb(i: String?,j: String?){
mDataBind.mWebView.webChromeClient = WebChromeClient()
mDataBind.mWebView.settings.javaScriptEnabled = true
mDataBind.mWebView.settings.domStorageEnabled = true
mDataBind.mWebView.settings.javaScriptCanOpenWindowsAutomatically = true
//mDataBind.mWebView.setBackgroundColor(0);//设置背景色
//mDataBind.mWebView.background.alpha = 0;//设置填充透明度(布局中一定要设置background,不然getbackground会是null)
mDataBind.mWebView.addJavascriptInterface(this, "test")
mDataBind.mWebView.loadUrl("file:///android_asset/live2D_title.html")
Handler().postDelayed(Runnable {
//2秒之后在这进行操作
mDataBind.mWebView.loadUrl("javascript:setL2($i,$j)");
}, 2000)
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/mWebView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp">
<TextView
android:id="@+id/tvBack"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:gravity="center"
android:textStyle="bold"
android:textColor="@color/black"
android:text="上一个"/>
<TextView
android:id="@+id/tvSelect"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:gravity="center"
android:textStyle="bold"
android:textColor="@color/black"
android:layout_centerInParent="true"
android:text="展示"/>
<TextView
android:id="@+id/tvNext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:gravity="center"
android:textStyle="bold"
android:textColor="@color/black"
android:layout_alignParentRight="true"
android:text="下一个"/>
</RelativeLayout>
</LinearLayout>
</layout>
activity_show
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<LinearLayout
android:layout_width="200px"
android:layout_height="300px"
android:orientation="vertical"
tools:context=".ShowActivity">
<WebView
android:id="@+id/mWebView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</layout>