Android-JsBridge实现本地H5混合开发

Android JsBridge 混合开发框架

0x01 Java 调用 Js

我们知道,native层调用h5,在WebView中,如果java要调用js的方法,

0x0101 loadUrl <4.4

Android4.4以前使用WebView.loadUrl("javascript:function()")

0x0102 evaluateJavascript >4.4

Android4.4以后,使用以下方式

1
2
3
4
5
6
webView.evaluateJavascript("javascript:function()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Toast.makeText(MainActivity.this, "onReceiveValue From JS: " + value, Toast.LENGTH_SHORT).show();
}
});

0x02 Js 调用 Java

h5层如何调native,有以下几种形式

0x0201 addJavascriptInterface >4.2

在4.2之前有安全隐患,JS可以动态获取到整个底层的实例信息,漏洞已经在Android 4.2上修复了,即使用@JavascriptInterface注解。

0x0202 shouldOverrideUrlLoading拦截自定义scheme

0x0203 onJsAlert,onJsConfirm,onJsPrompt

WebChromeClient对象中有三个方法,分别是onJsAlert,onJsConfirm,onJsPrompt,当js调用window对象的alert,confirm,prompt,WebChromeClient对象中的三个方法对应的就会被触发,进行拦截处理。

推荐使用onJsPrompt,使用频次最少,支持返回值。

1
2
3
4
5
6
7
8
9
10
11
override fun onJsPrompt(
view: WebView?,
url: String?,
message: String?,
defaultValue: String?,
result: JsPromptResult?
): Boolean {
val msg = handleMessage(message)
result?.confirm("Java 处理之后的 Json 数据:$msg")
return true
}

0x0204 onConsoleMessage

这是Android提供给Js调试在Native代码里面打印日志信息的API,同时这也成了其中一种Js与Native代码通信的方法。在Js代码中调用console.log(‘xxx’)方法。

0x03 自定义通信协议

jsbridge://className:callbackId/methodName?json

假设我们需要调用native层的Logger类的log方法,参数是msg,执行完成后js层要有一个回调,那么地址就如下

jsbridge://Logger:callbackId/log?{"msg":"message from js."}

RecyclerView实现瀑布流以及细节问题

RecyclerView实现瀑布流以及细节问题

1)使用 StaggeredGridLayoutManager

1
2
3
4
5
6
7
8
9
10
val layoutManager = StaggeredGridLayoutManager(2, RecyclerView.VERTICAL)
layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE// 禁止左右交换
recyclerView.layoutManager = layoutManager
// decoration
recyclerView.addItemDecoration(StaggeredDividerItemDecoration(16, true))
// adapter
mAdapter = PjListVPAdapter()
recyclerView.adapter = mAdapter
// animator
recyclerView.itemAnimator = DefaultItemAnimator()

2)如果需要Item之间的间隔,就需要自定义 ItemDecoration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 瀑布流ItemDecoration
* 必须配合RecyclerView的StaggeredGridLayoutManager一起使用
*
* @author Dench
* @data 2020-09-04
*/
class StaggeredDividerItemDecoration(
space: Int, // 间隔 pix
private val includeEdge: Boolean = false // 是否显示边距
) : ItemDecoration() {
private val space = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
space.toFloat(),
Resources.getSystem().displayMetrics
).toInt()

override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val lp = view.layoutParams as StaggeredGridLayoutManager.LayoutParams
val lm = parent.layoutManager as StaggeredGridLayoutManager
val spanIndex: Int = lp.spanIndex
val spanCount: Int = lm.spanCount
if (includeEdge) {
outRect.left = space * (spanCount - spanIndex) / spanCount
outRect.right = space * (spanIndex + 1) / spanCount
outRect.top = space
} else {
outRect.left = space * spanIndex / spanCount
outRect.right = space * (spanCount - spanIndex - 1) / spanCount
outRect.bottom = space
}
}
}
阅读更多

ARouter源码解析

ARouter源码解析

0x01 init ()

ARouter 的入口,初始化SDK ARouter.init(mApplication);

1
2
3
4
5
6
7
8
9
10
11
public static void init(Application application) {
if (!hasInit) { // 避免重复初始化
logger = _ARouter.logger; // 日志初始化
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application); // 正式初始化
if (hasInit) { // 初始化之后
_ARouter.afterInit(); // 管理拦截器的服务 InterceptorService 初始化
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}

_ARouter.init()

阅读更多

implementation compileOnly和api

implementation和api

implementationapi是取代之前的compile的,其中apicompile是一样的效果,implementation有所不同,通过implementation依赖的库只能自己库本身访问,举个例子,A依赖B,B依赖C,如果B依赖C是使用的implementation依赖,那么在A中是访问不到C中的方法的,如果需要访问,请使用api依赖

compile only

compile onlyprovided效果是一样的,只在编译的时候有效, 不参与打包

runtime only

runtimeOnlyapk效果一样,只在打包的时候有效,编译不参与

跟编译环境相关

  • test implementation

testImplementationtestCompile效果一样,在单元测试和打包测试apk的时候有效

  • debug implementation

debugImplementationdebugCompile效果相同, 在debug模式下有效

  • release implementation

releaseImplementationreleaseCompile效果相同,只在release模式和打包release包情况下有效

StatusBarHelper

StatusBarHelper

StatusBar 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
object StatusBarHelper {
/**
* 内容显示在状态栏下面(LAYOUT_FULLSCREEN) > 6.0
* true:白底黑字,false:黑底白字
*/
fun fitSystemBar(activity: Activity, light: Boolean = true) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
val window = activity.window
val decorView = window.decorView
var visibility = decorView.systemUiVisibility
visibility = visibility or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
visibility = if (light) {
visibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
visibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
decorView.systemUiVisibility = visibility

window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.statusBarColor = Color.TRANSPARENT
}

/**
* 调整状态栏文字、图标颜色 > 6.0
* true:白底黑字,false:黑底白字
*/
fun lightStatusBar(activity: Activity, light: Boolean = true) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
var window: Window = activity.window
var visibility = window.decorView.systemUiVisibility
visibility = if (light) {
visibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
visibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
window.decorView.systemUiVisibility = visibility
}


// 获取状态栏高度
fun getStatusBarHeight(activity: Activity): Int {
var result: Int = 0
var resId = activity.resources.getIdentifier("status_bar_height", "dimen", "android")
if (resId > 0) result = activity.resources.getDimensionPixelOffset(resId)
return result
}
}
阅读更多

多线程编程

多线程编程

0x01 生产者和消费者问题

1.BlockingQueue 阻塞队列实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 生产者
class Producer implements Runnable {
private final BlockingQueue<Integer> queue;

public Producer(BlockingQueue queue) {
this.queue = queue;
}

@Override
public void run() {
while (true) {
try {
queue.put(produce());
System.out.println(Thread.currentThread().getName() + " put a message, total = " + queue.size());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private int produce() {
int x = (int) (Math.random() * 10);
System.out.println(Thread.currentThread().getName() + " put: " + x);
return x;
}
}
阅读更多
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×