1. Introducción
Un proyecto reciente requiere que nuestros productos pasen por un túnel de red y proporcionen un SDK correspondiente. Obviamente, este proceso solo se puede realizar a través del desarrollo nativo. El autor nunca ha hecho desarrollo nativo ni aprendido Java, así que también lo pisé. Hay muchas trampas. Tomó dos días completar la tarea. Hoy, el sistema resume los próximos pasos. Dado que el desarrollo se basa en el negocio del autor, los pasos y los detalles pueden ser algo diferentes de otros artículos relacionados con el desarrollo de complementos nativos. . Por favor, también lea este artículo con una mentalidad dialéctica.
2. Lista de herramientas y materiales
Herramientas/Materiales | versión/nombre de la versión |
---|---|
HBuilder X |
3.1.4 |
Android Studio |
4.1.3 |
UNI-SDK |
[email protected]_20210305 |
Android Gradle Plugin Version |
4.1.1 |
Gradle Version |
6.5 |
3. Documento de integración SDK
El SDK nativo aquí se refiere al SDK proporcionado por otros fabricantes.
3.1 Introducción
- El paquete jar usado por el aar del túnel seguro
guava-18.0.jar
- El proyecto de terceros al que hace referencia el aar del túnel seguro
implementation 'org.bouncycastle:bcprov-jdk15on:1.55'
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.slf4j:slf4j-api:1.7.21'
复制代码
- Configure la dirección del servidor de túnel seguro, configure la dirección del servidor de túnel seguro en el archivo de recursos
<string name="client_vpn_server_host">xxx.xxx.xxx.xx:xxxx</string>
复制代码
- Después de que se inicialice el túnel de seguridad, obtendrá automáticamente la lista blanca (acción asíncrona) y persistirá localmente después de obtenerse con éxito. Por lo tanto, puede ser relativamente lento al inicializar el túnel de seguridad por primera vez (debido a las solicitudes de la red). )
3.2 Integración
El túnel seguro proporciona aar, y los documentos necesarios se han empaquetado en aar, solo se requiere el archivo build.gradle en el proyecto principal
dependencies{
...
implementation(name: 'MXSocksCore-x.x.x.xxxxxxxx', ext: 'aar')
...
}
复制代码
xxxxxxxxxxxx es el número de versión, también puede modificarlo usted mismo, pero debe corresponder con el nombre del archivo. Si no se hace referencia a aar en el archivo build.gradle del proyecto principal, se debe hacer referencia en el archivo build.gradle de el archivo principal
repositories {
flatDir {
dirs 'libs','子工程的libs的相对路径'
}
}
复制代码
Modifique la ruta relativa correspondiente en
Finalmente, coloque el aar en la carpeta libs del proyecto.
3.3 API
1. Inicializar el túnel
MXAppTunnel.getInstance().initAppTunnel(context, new AppTunnelInitComplete() {
@Override
public void appTunnelInitComplete() {
//初始化完成
}
@Override
public void appTunnelInitError(String msg) {
//初始化失败
}
});
复制代码
La inicialización del túnel debe completarse antes de su uso. Esta acción es una acción asíncrona. La lista blanca se obtendrá para el primer inicio y se almacenará localmente después de la adquisición exitosa. Los inicios posteriores no se bloquearán debido a la obtención de la lista blanca.
2. Salida de registro de túnel seguro
MXAppTunnel.getInstance().setLogPrintListener(new ILogPrint() {
@Override
public void log(String tag, String format, Object... objects) {
}
@Override
public void log(String tag, String msg) {
}
@Override
public void diagnosisLog(String msg) {
}
});
复制代码
3. Salida de información de túnel seguro
MXAppTunnel.getInstance().setProxyInfoCallBack(new IProxyInfoCallBack() {
@Override
public void sendProxyPort(int httpPort, int socksPort) {
//安全隧道两个服务器端口
//1、httpPort http本地代理服务器的端口
//2、socksPort socks本地代理服务器的端口
}
@Override
public void sendProxyWhiteList(List<String> list) {
//list 安全隧道白名单
}
});
复制代码
3.4 Uso del túnel seguro
El túnel seguro utiliza un proxy que debe configurarse manualmente para solicitudes http y https. Solo proporciona dos formas de configurar un proxy para solicitudes de red. La dirección del proxy es xxx.xxx y el puerto se genera en la tercera API.
1、Cliente Http
HttpHost httpHost = new HttpHost("xxx.x.x.x", xxxx);
httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, httpHost);
复制代码
2、HttpURLConexión
SocketAddress sa = new InetSocketAddress("xxx.x.x.x", xxxx);
//定义代理,此处的Proxy是源自java.net
Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,sa);
(HttpURLConnection) url.openConnection(proxy);
复制代码
3、HttpsURLConexión
SocketAddress sa = new InetSocketAddress("xxx.x.x.x", xxxx);
//定义代理,此处的Proxy是源自java.net
Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,sa);
(HttpsURLConnection) url.openConnection(proxy);
复制代码
Nota: Los puertos xxxx en el código de muestra son todos falsos y se debe usar la salida de puertos correspondiente en el tercer elemento de la API.
3.5 Demo
El archivo también proporciona una MainActivity.java
demostración.
package com.example.administrator.networkdemo.ui;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.administrator.networkdemo.R;
import com.minxing.vpn.MXAppTunnel;
import com.minxing.vpn.callback.AppTunnelInitComplete;
import com.minxing.vpn.callback.ILogPrint;
import com.minxing.vpn.callback.IProxyInfoCallBack;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Test";
private boolean isInit = false;
private int httpPort1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void initialize(View view) {
MXAppTunnel.getInstance().setProxyInfoCallBack(new IProxyInfoCallBack() {
@Override
public void sendProxyPort(int httpPort, int socksPort) {
//安全隧道两个服务器端⼝
//1、httpPort http本地代理服务器的端⼝
//2、socksPort socks本地代理服务器的端⼝
httpPort1 = httpPort;
Log.i(TAG, "httpPort: " + httpPort + " socksPort: " + socksPort);
Toast.makeText(MainActivity.this, "httpPort: " + httpPort + " socksPort: " + socksPort, Toast.LENGTH_LONG).show();
}
@Override
public void sendProxyWhiteList(List<String> list) {
//list 安全隧道⽩名单
StringBuilder stringBuilder = new StringBuilder();
for (String s : list) {
stringBuilder.append(s).append("\n");
}
Log.i(TAG, stringBuilder.toString());
Toast.makeText(MainActivity.this, stringBuilder.toString(), Toast.LENGTH_LONG).show();
}
});
MXAppTunnel.getInstance().initAppTunnel(MainActivity.this, new AppTunnelInitComplete() {
@Override
public void appTunnelInitComplete() {
//初始化完成
Log.i(TAG, "安全隧道初始化完成");
Toast.makeText(MainActivity.this, "安全隧道初始化完成", Toast.LENGTH_SHORT).show();
isInit = true;
}
@Override
public void appTunnelInitError(String msg) {
//初始化失败
Log.i(TAG, "安全隧道初始化失败: " + msg);
Toast.makeText(MainActivity.this, "安全隧道初始化失败: " + msg, Toast.LENGTH_SHORT).show();
}
});
MXAppTunnel.getInstance().setLogPrintListener(new ILogPrint() {
@Override
public void log(String tag, String format, Object... objects) {
Log.i(TAG, tag + " -1- format: " + format + " objects: " + objects);
}
@Override
public void log(String tag, String msg) {
Log.i(TAG, tag + " -2- msg: " + msg);
}
@Override
public void diagnosisLog(String msg) {
Log.i(TAG, " -3- msg: " + msg);
}
});
}
public void outputMXLog(View view) {
if (!isInit) {
Toast.makeText(MainActivity.this, "安全隧道未初始化", Toast.LENGTH_SHORT).show();
return;
}
}
public void outputMXInfo(View view) {
if (!isInit) {
Toast.makeText(MainActivity.this, "安全隧道未初始化", Toast.LENGTH_SHORT).show();
return;
}
request(httpPort1);
}
private void request(final int port) {
// OkHttpClient.Builder builder = new OkHttpClient.Builder();
// builder.connectTimeout(1, TimeUnit.MINUTES);
// Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", port));
// builder.proxy(proxy);
new Thread(new Runnable() {
@Override
public void run() {
String url = "http://xx.xx.xx.xxxx:xxxx/xxxxx/xxxxxx?params1=value1¶ms2=value2¶ms3=value3";
URL url1 = null;
try {
url1 = new URL(url);
SocketAddress sa = new InetSocketAddress("127.0.0.1", port);
//定义代理,此处的Proxy是源⾃java.net
Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,sa);
HttpURLConnection httpURLConnection =(HttpURLConnection) url1.openConnection(proxy);
httpURLConnection.setRequestMethod("POST");
//得到响应码
int responseCode = httpURLConnection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
//得到响应流
InputStream inputStream = httpURLConnection.getInputStream();
//将响应流转换成字符串
//String result = is2String(inputStream);//将流转换为字符串。
//Log.d("kwwl","result============="+result);
}
InputStream inputStream = httpURLConnection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
String tempLine;
StringBuilder resultBuffer = new StringBuilder();
while ((tempLine = reader.readLine()) != null) {
resultBuffer.append(tempLine);
}
Log.i(TAG, " -5- " + resultBuffer.toString());
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, " -4- " + e.getMessage());
}
}
}).start();
// Request request = new Request.Builder().url(url).get().build();
// Call call = builder.build().newCall(request);
// call.enqueue(new Callback() {
// @Override
// public void onFailure(Call call, IOException e) {
// final String s = e.getMessage();
// Log.e(TAG, s);
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
// }
// });
// }
//
// @Override
// public void onResponse(Call call, Response response) throws IOException {
// final String s = response.body().string();
// Log.e(TAG, s);
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
// }
// });
// }
// });
}
}
复制代码
3. Desarrollo
3.1 Operación del proyecto nativo
Para desarrollar complementos nativos, es una condición indispensable establecer un proyecto de proyecto nativo. Para facilitar el desarrollo, el proyecto UNI-SDK
en la carpeta se usa directamente aquí UniPlugin-Hello-AS
, y se arrastra directamente a Android Studio
(en lo sucesivo, AS
) y hizo clic en Archivo-Nuevo- Import Project
,
Después de seleccionar UniPlugin-Hello-AS
, haga clic en Aceptar y aparecerá toda la estructura de directorios.
Ahora presione el botón ejecutar para iniciar el proyecto de ejemplo.
3.2 Desarrollo de complementos
Primero siga el tutorial de desarrollo de complementos nativos de Android , paso a paso. No escribiré sobre la instalación de JDK y la instalación de AS. Estos no son grandes problemas. Cualquier artículo relacionado sobre Baidu puede publicarse.
gradle
Según la nota oficial, en general, prestamos atención a la configuración y tools.build:gradle
hacemos clic en la estructura del archivo-proyecto para ver nuestra versión cuando desarrollamos localmente.
Instale los pasos oficiales y cree uno nuevo. Module
Antes de eso, primero convertimos la estructura del proyecto a Project
la estructura del tipo, y luego hacemos clic en Archivo-Nuevo-New Module
seleccionar biblioteca
Configure el nombre y Module
el nombre del paquete, haga clic en Finalizar ( Finish
)
De acuerdo con el diseño oficial, una vez completada la nueva creación, debe configurar la Module
información recién creada build.gradle
, preste atención a sí Module
y app
no
El siguiente mensaje de error puede aparecer después de que se complete la nueva creación
Version 28 (intended for Android Pie and below) is the last version of the legacy support library, so we recommend that you migrate to AndroidX libraries when using Android Q and moving forward. The IDE can help with this: Refactor > Migrate to AndroidX... less... (Ctrl+F1)
Inspection info:There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion). Issue id: GradleCompatible
复制代码
La solución específica puede ir a Baidu, pero descubrí que esto parece ser solo una advertencia, de todos modos, al final no afectó mi compilación, operación y uso.
Primero, de acuerdo con las instrucciones de configuración del SDK de terceros, configure la dirección del servidor de túnel seguro en el archivo de recursos (tenga en cuenta que está debajo de la carpeta) main
y cree uniplugin_component
un nuevo archivo res consultando el formato de configuración de otros módulos. como ru.
Dado que nuestro túnel de red se implementa en el módulo de complemento Módulo, MXSDK
lo incluiremos Module
como libs
referencia.
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
//导入aar需要的配置
repositories {
flatDir {
dirs 'libs' //指定arr的导入路径,默认是当前Module的libs目录
}
}
dependencies {
/**引入uniSDK必要的依赖开始**/
//以com.等开头的是第三方的远程依赖库
compileOnly 'com.android.support:recyclerview-v7:28.0.0'
compileOnly 'com.android.support:support-v4:28.0.0'
compileOnly 'com.android.support:appcompat-v7:28.0.0'
compileOnly 'com.alibaba:fastjson:1.1.46.android'
compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs') //这种引入方式 ../app/libs 指定了app目录下的模块的rarr文件
/**引入uniSDK必要的依赖结束**/
/**安全隧道的aar引用的第三方工程开始**/
implementation 'org.bouncycastle:bcprov-jdk15on:1.55'
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.slf4j:slf4j-api:1.7.21'
//引入MX本地arr文件(根据dirs 'libs'这个路径直接引用当前Module-libs目录)
implementation(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
/**安全隧道的aar引用的第三方工程结束**/
}
复制代码
Una vez que se completa el acceso, run
después de un tiempo, se encuentra que no hay ningún error y el desarrollo personalizado comenzará a continuación. Crear una nueva clase
De acuerdo con los pasos oficiales, esta clase debe ser heredada UniModule
De acuerdo con el método de escritura en DEMO, los detalles son los siguientes
package com.example.kysin;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.minxing.vpn.MXAppTunnel;
import com.minxing.vpn.callback.AppTunnelInitComplete;
import com.minxing.vpn.callback.ILogPrint;
import com.minxing.vpn.callback.IProxyInfoCallBack;
import java.util.List;
import io.dcloud.feature.uniapp.common.UniModule;
public class tunnel extends UniModule {
private static final String TAG = "Test";
private boolean isInit = false;
private int httpPort1;
public void initialize(View view) {
MXAppTunnel.getInstance().setProxyInfoCallBack(new IProxyInfoCallBack() {
@Override
public void sendProxyPort(int httpPort, int socksPort) {
//安全隧道两个服务器端⼝
//1、httpPort http本地代理服务器的端⼝
//2、socksPort socks本地代理服务器的端⼝
httpPort1 = httpPort;
Log.i(TAG, "httpPort: " + httpPort + " socksPort: " + socksPort);
Toast.makeText(MainActivity.this, "httpPort: " + httpPort + " socksPort: " + socksPort, Toast.LENGTH_LONG).show();
}
@Override
public void sendProxyWhiteList(List<String> list) {
//list 安全隧道⽩名单
StringBuilder stringBuilder = new StringBuilder();
for (String s : list) {
stringBuilder.append(s).append("\n");
}
Log.i(TAG, stringBuilder.toString());
Toast.makeText(MainActivity.this, stringBuilder.toString(), Toast.LENGTH_LONG).show();
}
});
MXAppTunnel.getInstance().initAppTunnel(MainActivity.this, new AppTunnelInitComplete() {
@Override
public void appTunnelInitComplete() {
//初始化完成
Log.i(TAG, "安全隧道初始化完成");
Toast.makeText(MainActivity.this, "安全隧道初始化完成", Toast.LENGTH_SHORT).show();
isInit = true;
}
@Override
public void appTunnelInitError(String msg) {
//初始化失败
Log.i(TAG, "安全隧道初始化失败: " + msg);
Toast.makeText(MainActivity.this, "安全隧道初始化失败: " + msg, Toast.LENGTH_SHORT).show();
}
});
MXAppTunnel.getInstance().setLogPrintListener(new ILogPrint() {
@Override
public void log(String tag, String format, Object... objects) {
Log.i(TAG, tag + " -1- format: " + format + " objects: " + objects);
}
@Override
public void log(String tag, String msg) {
Log.i(TAG, tag + " -2- msg: " + msg);
}
@Override
public void diagnosisLog(String msg) {
Log.i(TAG, " -3- msg: " + msg);
}
});
}
}
复制代码
Aquí el IDE le indicará "no se puede resolver el símboloMainActivity
Esto implica el "contexto actual" De acuerdo con el Activity
método tradicional, podemos integrar directamente Activity
y luego escribir Activity.this
o pasar getApplicationContext
para obtener el contexto de ejecución. Pero la documentación oficial dice:
Activity
del método de adquisición. AlmUniSDKInstance.getContext()
obligarActivity
. Se recomiendainstanceof Activity
hacer un juicio antes de forzarlo, por lo que aquí modificamos el método de encapsulación y usamos el método de escrituramUniSDKInstance.getContext()
alternativoActivity.this
package com.example.kysin;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.minxing.vpn.MXAppTunnel;
import com.minxing.vpn.callback.AppTunnelInitComplete;
import com.minxing.vpn.callback.ILogPrint;
import com.minxing.vpn.callback.IProxyInfoCallBack;
import java.util.List;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.common.UniModule;
public class Tunnel extends UniModule {
private static final String TAG = "Test";
private boolean isInit = false;
private int httpPort1;
@UniJSMethod(uiThread = false)
public void initialize() {
Log.i(TAG, "11111");
MXAppTunnel.getInstance().setProxyInfoCallBack(new IProxyInfoCallBack() {
@Override
public void sendProxyPort(int httpPort, int socksPort) {
//安全隧道两个服务器端⼝
//1、httpPort http本地代理服务器的端⼝
//2、socksPort socks本地代理服务器的端⼝
httpPort1 = httpPort;
Log.i(TAG, "httpPort: " + httpPort + " socksPort: " + socksPort);
Toast.makeText((Activity)mUniSDKInstance.getContext(), "httpPort: " + httpPort + " socksPort: " + socksPort, Toast.LENGTH_LONG).show();
}
@Override
public void sendProxyWhiteList(List<String> list) {
//list 安全隧道⽩名单
StringBuilder stringBuilder = new StringBuilder();
for (String s : list) {
stringBuilder.append(s).append("\n");
}
Log.i(TAG, stringBuilder.toString());
Toast.makeText((Activity)mUniSDKInstance.getContext(), stringBuilder.toString(), Toast.LENGTH_LONG).show();
}
});
MXAppTunnel.getInstance().initAppTunnel((Activity)mUniSDKInstance.getContext(), new AppTunnelInitComplete() {
@Override
public void appTunnelInitComplete() {
//初始化完成
Log.i(TAG, "安全隧道初始化完成");
Toast.makeText((Activity)mUniSDKInstance.getContext(), "安全隧道初始化完成", Toast.LENGTH_SHORT).show();
isInit = true;
}
@Override
public void appTunnelInitError(String msg) {
//初始化失败
Log.i(TAG, "安全隧道初始化失败: " + msg);
Toast.makeText((Activity)mUniSDKInstance.getContext(), "安全隧道初始化失败: " + msg, Toast.LENGTH_SHORT).show();
}
});
MXAppTunnel.getInstance().setLogPrintListener(new ILogPrint() {
@Override
public void log(String tag, String format, Object... objects) {
Log.i(TAG, tag + " -1- format: " + format + " objects: " + objects);
}
@Override
public void log(String tag, String msg) {
Log.i(TAG, tag + " -2- msg: " + msg);
}
@Override
public void diagnosisLog(String msg) {
Log.i(TAG, " -3- msg: " + msg);
}
});
}
}
复制代码
3.3 Pruebas de complementos en la aplicación nativa
Después de escribir, se debe realizar la prueba de inicialización del túnel. Para implementar esta prueba de invocación en el proyecto nativo Module
, se requieren los siguientes pasos:
dcloud_uniplugins.json
Declare eModule
introduzca el complemento nativo a través de- Cree un nuevo
UNI
proyecto personalizado y escriba el método de llamada correspondiente
Entonces, nuestro primer paso es declarar el complemento en el proyecto nativo, como se describe en el documento oficial: archivo UniPlugin-Hello-AS
bajo el proyecto . Agregue lo que desea registrar en el app-src-main-assets/dcloud_uniplugins.json
nodo o moudles
Module
Component
{
"nativePlugins": [
{
"plugins": [
{
"type": "module",
"name": "TestModule",
"class": "io.dcloud.uniplugin.TestModule"
}
]
},
{
"plugins": [
{
"type": "component",
"name": "myText",
"class": "io.dcloud.uniplugin.TestText"
}
]
},
{
"hooksClass": "",
"plugins": [
{
"type": "module",
"name": "DCloud-RichAlert",
"class": "uni.dcloud.io.uniplugin_richalert.RichAlertModule"
}
]
},
{
"plugins": [
{
"type": "module",
"name": "test-Module", //这个名字可以随便取,只要和UNI项目中requireNativePlugin的相同就行
"class": "com.example.kysin.Tunnel"
}
]
}
]
}
复制代码
Luego vaya al app
módulo build.gradle
para agregar el nuevo complemento de Moudle
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.HBuilder.UniPlugin"
minSdkVersion 21
targetSdkVersion 26 //建议此属性值设为21 io.dcloud.PandoraEntry 作为apk入口时 必须设置 targetSDKVersion>=21 沉浸式才生效
versionCode 1
versionName "1.0"
multiDexEnabled true
ndk {
abiFilters 'x86','armeabi-v7a'
}
}
buildTypes {
release {
zipAlignEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
zipAlignEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//使用uniapp时,需复制下面代码
/*代码开始*/
aaptOptions {
additionalParameters '--auto-add-overlay'
//noCompress 'foo', 'bar'
ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"
}
/*代码结束*/
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "com.android.support:support-v4:28.0.0"
implementation "com.android.support:appcompat-v7:28.0.0"
/*uniapp所需库-----------------------开始*/
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.facebook.fresco:fresco:1.13.0'
implementation "com.facebook.fresco:animated-gif:1.13.0"
/*uniapp所需库-----------------------结束*/
// 基座需要,必须添加
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.alibaba:fastjson:1.1.46.android'
// 添加uni-app插件
implementation project(':uniplugin_component')
implementation project(':uniplugin_module')
implementation project(':uniplugin_richalert')
// 添加自定义插件
implementation project(':testModule') //和你新建Module的文件夹名字保持一致
}
复制代码
testModule
Gradle.builde
La importación de archivos locales en el módulo arr
, he resumido las siguientes situaciones
//app工程libs如没有这个arr文件会报Coulad not resolve:MXSocksCore-release_6.8.0_stable_socks_jar_160:
//app工程libs如没有这个arr文件会报Duplicate class com.google.common.annotations.Beta found in modules MXSocksCore-release_6.8.0_stable_socks_jar_160-runtime(:MXSocksCore-release_6.8.0_stable_socks_jar_160:) adn MXSocksCore-release_6.8.0_stable_socks_jar_160-runtime(MXSocksCore-release_6.8.0_stable_socks_jar_160.arr)
//app无法编译运行
implementation(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
//情况同上
api(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
//app工程libs如没有这个arr文件会报警告,但是程序会正常启动,但是自定义的Module事件无法触发
//Missing class:com.mingxing.vqn.callback.ApptunnellnitCompelet
//Missing class: com.minxing.vpn.callback.IProxyInfoCallBack
//Missing class: com.minxing.vpn.callback.ILogPrint
//app工程libs有这个arr文件才能不报/Missing class,能正常运行
compileOnly(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
//app工程libs如没有这个arr文件也能正常运行
//但是打包arr时报错:Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken because the classes and Android resources from any local .aar file dependencies would not be packaged in the resulting AAR. Previous versions of the Android Gradle Plugin produce broken AARs in this case too (despite not throwing this error). The following direct local .aar file dependencies of the :testModule project caused this error: C:\Users\jnp\Desktop\jianshu\[email protected]_20210305\UniPlugin-Hello-AS\testModule\libs\MXSocksCore-release_6.8.0_stable_socks_jar_160.aar
api fileTree(include: ['MXSocksCore-release_6.8.0_stable_socks_jar_160.aar'], dir: './libs')
//app工程libs如没有这个arr文件也能正常运行
//但是打包arr时报错:Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken because the classes and Android resources from any local .aar file dependencies would not be packaged in the resulting AAR. Previous versions of the Android Gradle Plugin produce broken AARs in this case too (despite not throwing this error). The following direct local .aar file dependencies of the :testModule project caused this error: C:\Users\jnp\Desktop\jianshu\[email protected]_20210305\UniPlugin-Hello-AS\testModule\libs\MXSocksCore-release_6.8.0_stable_socks_jar_160.aar
implementation fileTree(dir: 'libs', include: ['*.aar'])
复制代码
En base a esto, este artículo solo puede elegir compileOnly(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
una forma de arr
hacer referencia a los complementos de terceros. Aquí, debe colocar una copia del paquete arr de terceros en la carpeta app
del módulo .libs
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
//导入aar需要的配置
repositories {
flatDir {
dirs 'libs' //指定arr的导入路径,默认是当前Module的libs目录
}
}
dependencies {
/**引入uniSDK必要的依赖开始**/
//以com.等开头的是第三方的远程依赖库
compileOnly 'com.android.support:recyclerview-v7:28.0.0'
compileOnly 'com.android.support:support-v4:28.0.0'
compileOnly 'com.android.support:appcompat-v7:28.0.0'
compileOnly 'com.alibaba:fastjson:1.1.46.android'
compileOnly fileTree(include: ['uniapp-v8-release.aar'], dir: '../app/libs') //这种引入方式 ../app/libs 指定了app目录下的模块的arr文件
/**引入uniSDK必要的依赖结束**/
/**安全隧道的aar引用的第三方工程开始**/
implementation 'org.bouncycastle:bcprov-jdk15on:1.55'
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.slf4j:slf4j-api:1.7.21'
//引入MX本地arr文件(根据dirs 'libs'这个路径直接引用当前Module-libs目录)
compileOnly(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
/**安全隧道的aar引用的第三方工程结束**/
}
复制代码
Luego vaya a crear un nuevo UNI
proyecto y escriba el código para llamar al complemento nativo
Una vez completada la escritura, haga clic en Publicar-Paquete local de la aplicación nativa-Generar recursos de la aplicación del paquete local
Elimine todo el archivo app-src-main-assets-apps
en el directorio del proyecto original , y luego pegue el archivo que ha empaquetado y renombrado en el directorio que acaba de eliminar. Aquí hay un ejemplo.__UNI__BCEC007
APPID
apps
__UNI__911FD69
Luego ve a app-src-main-assets-data-dcloud_control.xml
modificarlo appid
al que acabas de copiarappid
Haga clic en run
y, a continuación, haga clic en el icono de la página de inicio de la aplicación para llamar al método nativo y ver logcat
el registro de entrada
Como se puede ver arriba, la llamada se puede hacer normalmente. Prueba de complemento exitosa
3.4 Embalaje enchufable
El primer paso del paquete de complementos sigue siendo muy simple, haga clic en Gradle
el icono en el lado derecho del IDE, busque uniPlugin-Hello-AS-testModule-Tasks-other-assembleRelease
, haga doble clicassembleRelease
testModule-build-outputs-arr
Encuentre nuestro complemento en la carpeta testModule-release.arr
de acuerdo con la generación de documentos oficiales.uni-app
Antes de empaquetar, debe recordar manifest.json
seleccionar el complemento nativo local y encontrará que el nombre del complemento es el campo package.json
en el archivo name
.
Al empaquetar, elija ejecutar (ejecutar en el teléfono móvil o en el emulador), cree una base de depuración personalizada, espere a que se complete el empaque y haga clic para ejecutarlo.
Este artículo se cita del renacuajo sin soporte de Rare Earth Nuggets.