上一篇讲了如何使用Capacitor打包安卓APK,在使用Capacitor开发的时候,我们会经常使用到它的内置插件,但,肯定会有插件不满足我们使用的时候。 这时候我们需要自定义一个我们自己的插件。
Capacitor原生给我们提供了很多插件,有官方插件和社区插件。
详细插件信息可以到官方查看capacitorjs.com/docs/plugin…
整体插件的封装还比较简单,比Uniapp原生插件容易多了,Uniapp原生插件 + 引用第三方SDK,那是一个恶心。
先描述一下,我想要写的插件
我在打包HTML的时候,遇到超过4G的资源,那么就会无法打包,因为安卓本身限制了最大只能打包4G,并且安卓设备无法安装超过4G的APK.
这时候,就需要在线去下载资源到本地,类似于王者荣耀的下载资源包功能。
具体功能如下:
- 先下载一个空壳的APK
- 进入程序后,请求版本更新
- 返回下载文件的JSON,跟本地保存的JSON进行diff对比,
- 增量更新,下载文件到本地目录,保存新版本信息到本地
- 新建一个Webview,展示读取下载的HTML
请求、文件下载、读取都有官方插件可以使用,唯独没有可以动态创建一个Webview去加载我下载下来的HTML。
那么,我需要写的插件就是去新建一个Webview加载本地HTML。
插件命名为:LoadLocalHtml
创建插件
创建一个class
打开Android studio,来到src main下面的 example app 下面创建一个Java Class。
在这个Class中会写我们主要的业务逻辑。
我创建了一个Class:LoadLocalHtml
LoadLocalHtml.java 实现
package com.example.app;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
// 插件名称,在web端注册的时候会使用到
@CapacitorPlugin(name = "LoadLocalHtml")
public class LoadLocalHtmlPlugin extends Plugin {
// 插件方法,通过这个注解暴露方法,到时候web端就可以去调用这个方法
@PluginMethod
public void loadWebPage(PluginCall call) {
// 获取web端传入的参数,此处传入了一个{ uri: string }
String contentUriString = call.getString("uri");
// 这一段是我的业务逻辑,大家看的时候可以适当忽略
if (contentUriString != null) {
Uri contentUri = Uri.parse(contentUriString);
String fileContent = readFileContent(contentUri);
String baseUrl = contentUriString.substring(0, contentUriString.lastIndexOf("/") + 1);
if (fileContent != null) {
Context context = getContext();
getActivity().runOnUiThread(new Runnable() {
@SuppressLint("SetJavaScriptEnabled")
@Override
public void run() {
// 创建一个 FrameLayout 作为容器
FrameLayout layout = new FrameLayout(context);
// 创建Webview并且设置相关权限
WebView webView = new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
// 加载页面
webView.loadDataWithBaseURL(baseUrl, fileContent, "text/html", "UTF-8", null);
// 监测Webview错误
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Log.e("WebView Error", "Error: " + description);
}
});
// 将 WebView 添加到 FrameLayout 中
layout.addView(webView);
// 获取当前 Activity 的根视图
ViewGroup rootView = (ViewGroup) getActivity().getWindow().getDecorView().getRootView();
// 将 FrameLayout 添加到根视图中
rootView.addView(layout);
JSObject ret = new JSObject();
ret.put("message", "Web page loaded successfully");
// 返回结果给web端
call.resolve(ret);
}
});
} else {
call.reject("Failed to read file content");
}
} else {
call.reject("Content URI is null");
}
}
private String readFileContent(Uri contentUri) {
try {
ContentResolver contentResolver = getContext().getContentResolver();
InputStream inputStream = contentResolver.openInputStream(contentUri);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
inputStream.close();
return stringBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
注册插件
在MainActivity.java文件中
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 注册插件
registerPlugin(LoadLocalHtmlPlugin.class);
super.onCreate(savedInstanceState);
}
}
在web端
新建一个js或者ts文件,用于注册插件
LoadLocalhtmlPlugin.ts
import { registerPlugin } from '@capacitor/core'
export interface LoadLocalHtml {
// 这是我们在插件中定义的方法,接收一个对象,里面有个uri属性
loadWebPage(options: { uri: string }): Promise<{ value: string }>
}
// LoadLocalHtml 为我们刚刚创建的插件名称
const LoadLocalHtml = registerPlugin<LoadLocalHtml>('LoadLocalHtml')
export default LoadLocalHtml
插件的使用
<script setup lang="ts">
import LoadLocalHtml from './utils/LoadLocalhtmlPlugin'
onMounted(() => {
const path = 'xxxx'
LoadLocalHtml.loadWebPage({ uri: path })
})
</script>