APLICACIÓN UNI --- Práctica de desarrollo de complementos nativos de Android (2)

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. He escrito un artículo sobre solicitudes de datos a través de métodos proxy, pero esta vez El método en el El lado de Android es usar el método NBA para solicitar datos, y el desarrollo del complemento nativo comenzará a continuación.

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

Primero verifique si su gradle cumple con los requisitos de acuerdo con las precauciones de la versión oficial de gradel

Como Android Gradle Plugin Versiony Gradle Versionen AS File-Project Structurepuede ver

3. Documento de integración SDK

3.1 Introducción

3.1.1 Integración del entorno:

  1. libsecure_portal.soLa biblioteca solo se coloca libs\armeabidebajo de la carpeta, armeabi-v7a,armeabi64-v8no la coloque en otros directorios.

  2. libsecure_portal.jarEl archivo se coloca en el directorio libs.

  3. Archivo de configuración build.gradle, agregue la siguiente configuración

defaultConfig {
    ndk {
            abiFilters 'armeabi'
    }
}

sourceSets {
    main {
            jniLibs.srcDirs = ["libs"]
    }
}

复制代码
  1. AndroidMainfest.xmlAgregar permisos en
<service 
    android:name="com.secure.sportal.sdk.NBA.SPNCService"
    android:permission="android.permission.BIND_NBA_SERVICE">
    <intent-filter>
            <action android:name="android.net.NBAService" />
    </intent-filter>
</service>
复制代码

Después de completar los 4 pasos anteriores, la configuración del entorno está completa.

3.1.2 Integración de código

1. Configure los parámetros de la NBA y conéctese a la NBA

private static final int REQUEST_NC_CODE = 1234;
public void connectNBA() {
	Properties params = new Properties();
	// 配置NBA服务器地址,端口
	params.setProperty(SPNBAClient.PARAM_NBA_HOST, "NBA公网地址 ");
	params.setProperty(SPNBAClient.PARAM_NBA_PORT, "NBA公网端口");

	// 认证服务器名称,这里建议填空,默认使用第一个认证服务器
	params.setProperty(SPNBAClient.PARAM_AUTH_SERVER, "");
	// SSLNBA 登录用户名
	params.setProperty(SPNBAClient.PARAM_AUTH_USERNAME, "username");
	// SSLNBA 登录密码
	params.setProperty(SPNBAClient.PARAM_AUTH_PASSWORD, "password");

	// 可直接在UI主线程调用login()方法,SDK内部自动在非UI线程完成工作,
	// 并通过异步回调方式通知执行结果。login()会立即返回,不会阻塞。
	SPNBAClient.login(this, params, new SPNBAClient.OnNBALoginCallback() {
		@Override
		public void onNBALoginMessage(int msgid, String msg) {
			//SSLNBA的登录结果会回调该函数
			if (msgid == SPNBAClient.MSGID_LOGIN_SUCC) {
				// SSLNBA 登录成功
				startTunnel(); // 启动nc网卡
			} else if (msgid == SPNBAClient.MSGID_LOGIN_FAIL) {
				// SSLNBA 登录失败,打印出失败信息
				Log.e(TAG, "连接服务器失败 msgid is " + msgid + ", msg is " + msg);
			}
		}
	});
}
复制代码

2. Inicie la tarjeta de red NC del sistema Android después de que la conexión NBA se haya realizado correctamente. Nota: Cuando se llame a esta función por primera vez, aparecerá un cuadro de autorización del sistema que le preguntará al usuario si desea permitir el establecimiento de una red virtual. tarjeta Debe hacer clic en "Permitir" aquí. Si hace clic en "rechazar" por primera vez. Debe desinstalar la aplicación, reiniciar el teléfono y luego reinstalar la aplicación, y luego aparecerá nuevamente el cuadro de autorización para que el usuario elija. ! !

private void startTunnel() {
	//判断网关配置是否有下发NC业务,如没有下发,则不需要建立nc网卡。
	if (SPNBAClient.needsNBATunnel()) {
		Intent intent = NBAService.prepare(getApplicationContext());
		if (intent != null) {
			// 用户从未同意过NC权限,启动对话框向用户确认权限
			Log.e(TAG, "用户未授权NC权限,启动失败");
			startActivityForResult(intent, REQUEST_NC_CODE);
		} else {
			// 用户已确认权限可直接启动NC
			Log.d(TAG, "startNBATunnel...");
			SPNBAClient.startNBATunnel(this, true, 0); //该函数最终会启动nc网卡
		}
	} else {
		Log.e(TAG, "服务器未配置NC业务!");
	}
}
复制代码

3. ReescribironActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (requestCode == REQUEST_NC_CODE) {
		log.d("result is " + resultCode);
		if (resultCode == RESULT_OK) {
			SPNBAClient.startNBATunnel(this, true, 0); //该函数最终会启动nc网卡
			Log.d(TAG, "登录成功,建立NC网卡成功");
		}
	}
}
复制代码

4. Desarrollo

4.1 Proyecto nativo en ejecución

Para desarrollar complementos nativos, es una condición indispensable establecer un proyecto de proyecto nativo. Para facilitar el desarrollo, el proyecto UNI-SDKen 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.

4.2 Desarrollo de complementos

Primero siga el tutorial de desarrollo de complementos nativos de Android , paso a paso. De acuerdo con el diseño oficial, una vez completada la nueva creación, es necesario configurar la Moduleinformación recién creada. Tenga en cuenta que no build.gradlees la instalación de los pasos oficiales, y cree uno nuevo. Antes de eso, primero convertimos la estructura del proyecto a la estructura del tipo y luego haga clic en Archivo-Nuevo-ModuleappModuleProjectNew Module

seleccionar biblioteca

Configure el nombre y Moduleel 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 Moduleinformación recién creada build.gradle, preste atención a sí Moduley appno

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.

4.2.1 Configuración SDK

Siga las instrucciones de configuración del SDK de terceros

  1. libsecure_portal.soLa biblioteca solo se coloca libs\armeabidebajo de la carpeta, armeabi-v7a,armeabi64-v8no la coloque en otros directorios.

  2. libsecure_portal.jarEl archivo se coloca en el directorio libs.

  1. Archivo de configuración build.gradle, agregue la siguiente configuración
defaultConfig {
	ndk {
		abiFilters 'armeabi'
	}
}

sourceSets {
	main {
		jniLibs.srcDirs = ["libs"]
	}
}

复制代码

De acuerdo con la descripción de configuración anterior, modifique NBATunnel moduleelbuild.gradle

//修改前
plugins {
    id 'com.android.library'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    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
    }
}

dependencies {

    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
复制代码

después de la modificación

plugins {
    id 'com.android.library'
}

android {
    compileSdkVersion 30

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        ndk {
            abiFilters "armeabi-v7a", "x86" //this 货
        }
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
    }
    sourceSets {
        main {
              //在 AS 中它会自动去加载 jniLibs 目录中的 *.so 文件(工程目录而不是在module目录)。如果你放在了其它任何目录,你必须要告诉它你将这些文件放在那里了(重定向)。
            // 这里我写 `libs`,它就会去当前module的 `libs` 目录中找,你也可以放在其它任何目录中。
            jniLibs.srcDirs = ["libs"]
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

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必要的依赖结束**/
    //结合上面的 jniLibs.srcDirs = ["libs"]
    implementation files('libs/libsecure_portal.jar')
}
复制代码

Para la importación de archivos locales en NBATunnelel módulo , he resumido las siguientes situacionesGradle.buildearr

//可以正常的运行,但是打包会出错
//implementation files('libs/libsecure_portal.jar')
//无法编译Could not find method filetree() for arguments [{dir=libs, include=[*.jar]}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
//implementation filetree(dir: 'libs', include: ['*.jar'])
//Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
//implementation(name: 'libsecure_portal.jar', ext: 'jar')
//可以通过编译,但是运行的时候会提示找不到类里面的方法
//compileOnly files('libs/libsecure_portal.jar')
//可以通过编译和运行
//compile fileTree(dir: 'libs', include: ['*.jar'])
环境配置完毕厚,下面进行业务代码的开发
复制代码
  1. AndroidMainfest.xmlAgregar permisos en
<service 
        android:name="com.secure.sportal.sdk.NBA.SPNCService"
        android:permission="android.permission.BIND_NBA_SERVICE">
        <intent-filter>
                <action android:name="android.net.NBAService" />
        </intent-filter>
</service>
复制代码

La configuración del entorno está completa y el código comercial se desarrolla a continuación.

4.2.2 Realización de negocios de código nativo

De acuerdo con los pasos oficiales, esta clase debe ser heredada UniModuleDe acuerdo con el método de escritura en DEMO, los detalles son los siguientes

package com.example.NBAmodule;

import android.app.Activity;
import android.content.Intent;
import android.net.NBAService;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.secure.sportal.sdk.SPNBAClient;

import java.util.Properties;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

import static android.app.Activity.RESULT_OK;

public class NBATunnel extends UniModule {
    private static final int REQUEST_NC_CODE = 1234;
    String TAG = "结果";
    private UniJSCallback callback;
    @UniJSMethod(uiThread = false)
    public void connectNBA(JSONObject options, UniJSCallback callback1) {
        callback = callback1;
        //获取JS层传递过来的网关账号和密码
        String username = options.getString("NBAUsername");
        String password = options.getString("NBAPassword");
        Log.i(TAG, username);
        Log.i(TAG, password);
        Properties params = new Properties();
        params.setProperty(SPNBAClient.PARAM_NBA_HOST, "xxx.xxx.xxx.xx");
        params.setProperty(SPNBAClient.PARAM_NBA_PORT, "xxx");
        params.setProperty(SPNBAClient.PARAM_AUTH_SERVER, "");
        params.setProperty(SPNBAClient.PARAM_AUTH_USERNAME, username);
        params.setProperty(SPNBAClient.PARAM_AUTH_PASSWORD, password);
        // 可直接在UI主线程调用login()方法,SDK内部自动在非UI线程完成工作,
        // 并通过异步回调方式通知执行结果。login()会立即返回,不会阻塞。
        SPNBAClient.login(mUniSDKInstance.getContext(), params, new SPNBAClient.OnNBALoginCallback() {
            @Override
            public void onNBALoginMessage(int msgid, String msg) {
                //SSLNBA的登录结果会回调该函数
                if ( msgid==SPNBAClient.MSGID_LOGIN_SUCC )
                {
                    Log.i("msgid", String.valueOf(msgid));
                    Log.i("msgid", msg);
                    // SSLNBA 登录成功
                    startTunnel(); // 启动nc网卡
                }
                else if ( msgid==SPNBAClient.MSGID_LOGIN_FAIL )
                {
                    // SSLNBA 登录失败,打印出失败信息
                    callback.invoke("网关登录失败:"+msg);
                }
            }
        });
    }
    @UniJSMethod(uiThread = false)
    private void startTunnel() {
        //判断网关配置是否有下发NC业务,如没有下发,则不需要建立nc网卡。
        if (SPNBAClient.needsNBATunnel())
        {
            Intent intent = NBAService.prepare(mUniSDKInstance.getContext());
            if (intent != null)
            {
                // 用户从未同意过NC权限,启动对话框向用户确认权限
//                Log.e(TAG, "用户未授权NC权限,启动失败");
                callback.invoke("请求权限");
                ((Activity)mUniSDKInstance.getContext()).startActivityForResult(intent, REQUEST_NC_CODE);
            }
            else
            {
                // 用户已确认权限可直接启动NC
                Log.d(TAG, "startNBATunnel...");
                SPNBAClient.startNBATunnel(mUniSDKInstance.getContext(), true, 0);//该函数最终会启动nc网卡
                callback.invoke("网关登录成功");
            }
        }
        else
        {
            callback.invoke("服务器未配置NC业务");
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d("结果","result is " + resultCode+requestCode+data);
        if (requestCode == REQUEST_NC_CODE)
        {
            callback.invoke("权限许可成功");
            if (resultCode == RESULT_OK)
            {
                SPNBAClient.startNBATunnel(mUniSDKInstance.getContext(), true, 0);//该函数最终会启动nc网卡
                callback.invoke("登录成功,建立NC网卡成功");
            }
        }
        else
        {
            callback.invoke("权限许可失败");
        }
    }
}
复制代码

4.2.3 Escritura del código UNI

Cree un nuevo proyecto UNI y escriba el código para llamar al complemento nativo

<template>
	<view>
		<!--状态栏 -->
		<view class="status_bar"></view>
		<view class="login">
			<view class="content">
				<!-- 头部logo -->
				<view class="header">
					<image src="@/static/images/logo.png"></image>
				</view>
				<text class="title"></text>
				<!-- 主体表单 -->
				<view class="main">
					<wInput v-model="account" type="text" placeholder="账号" :focus="isFocus" :disabled="disabled">
					</wInput>
					<wInput v-model="password" type="password" placeholder="密码" :disabled="disabled"></wInput>
				</view>
				<wButton class="wbutton" text="登 录" :rotate="isRotate" @click="startLogin"></wButton>
			</view>
			<yomol-upgrade :type="upgradeType" :url="upgradeUrl" title="发现新版本" :content="upgradeContent"
				ref="yomolUpgrade"></yomol-upgrade>
			<!-- 网关modal -->
			<tui-modal :show="modal" :custom="true" fadeIn >
				<view class="tui-modal-custom">
					<view class="tui-prompt-title">NBA账号</view>
					<input class="tui-modal-input"   v-model="NBAUsername" />
					<view class="tui-prompt-title">NBA密码</view>
					<input class="tui-modal-input password"   v-model="NBAPassword" />
					<tui-button height="72rpx" :size="28" shape="circle" @click="requestNBA">提交</tui-button>
				</view>
			</tui-modal>
		</view>
	</view>
</template>

<script>
	let tunnel
	if (uni.getSystemInfoSync().platform == "android")
		tunnel = uni.requireNativePlugin('NBATunnel')
	if (uni.getSystemInfoSync().platform == "ios")
		tunnel = uni.requireNativePlugin("NBATunnel-NBATunnel")
	import wInput from "@/components/watch-login/watch-input.vue"; 
	import wButton from "@/components/watch-login/watch-button.vue"; 
	import tuiModal from '@/components/tui-modal/tui-modal.vue';
	import { DbHelper } from "@/js/db.js";
	export default {
		data() {
			return {
				account: "",
				password: "",
				isRotate: false, //是否加载旋转
				isFocus: false, // 是否聚焦
				disabled: false,
				upgradeType: "pkg", //pkg 整包 wgt 升级包
				upgradeContent: "", //更新内容
				upgradeUrl: "", //更新地址
				NBAUsername:'',
				NBAPassword:'',
				modal:false,
			};
		},
		components: {
			wInput,
			wButton,
		},
		async mounted() {
			await DbHelper.init();
			this.isLogin();
		},
		methods: {
			async isLogin() {
				if (uni.getSystemInfoSync().platform == "android")
				{
					uni.showLoading({mask:true})
					//无本地NBA数据
					if(!uni.getStorageSync('NBAInfo'))
					{
						uni.hideLoading()
						let [,res] = await uni.showModal({
							content: '即将发起NBA权限请求,请点击确认,若在此过程中退出应用或者拒绝了权限,需要重装本应用才能重新发起NBA权限请求!',
							showCancel:false,
						});
						this.modal = true
					}
					else//有本地NBA数据,说明之前已经建立了网卡
					{
						let NBAInfo =  uni.getStorageSync('NBAInfo')
						this.NBAUsername = NBAInfo.NBAUsername
						this.NBAPassword = NBAInfo.NBAPassword
						uni.hideLoading()
						await this.requestNBA()
					}
				}
				if (uni.getSystemInfoSync().platform == "ios") 
				{
					uni.showLoading({mask:true})
					//无本地NBA数据
					if(!uni.getStorageSync('NBAInfo'))
					{
						uni.hideLoading()
						let [,res] = await uni.showModal({
							content: '请输入正确的NBA账号密码才能后续登录!',
							showCancel:false,
						});
						this.modal = true
					}
					else//有本地NBA数据,说明之前已经建立了网卡
					{
						let NBAInfo =  uni.getStorageSync('NBAInfo')
						this.NBAUsername = NBAInfo.NBAUsername
						this.NBAPassword = NBAInfo.NBAPassword
						uni.hideLoading()
						await this.requestNBA()
					}
					
				}
			},
			/**
			 * @description 连接NBA服务器
			 */
			async requestNBA(){
				return new Promise((resolve,rejcet) => {
					uni.showLoading({
						title: 'NBA连接中...',
						mask: true
					});
					if (!this.NBAUsername)
						return uni.showToast({
							title: "NBA账号不能为空!",
							icon: "none"
						}); // 	显示提示框
					if (!this.NBAPassword)
						return uni.showToast({
							title: "NBA密码不能为空!",
							icon: "none"
						});
					if (uni.getSystemInfoSync().platform == "android") 
					{
						tunnel.connectNBA({
							NBAUsername:this.NBAUsername,
							NBAPassword:this.NBAPassword
						},async res=>{
							this.modal = false
							uni.hideLoading()
							if(res == '网关登录成功' || res == '请求权限')
							{
								let NBAInfo = {
									NBAUsername:this.NBAUsername,
									NBAPassword:this.NBAPassword
								}
								uni.setStorageSync('NBAInfo',NBAInfo);
								let { account,password } = uni.getStorageSync("userInfo"); // 从本地缓存中同步获取指定 key 对应的内容。
								if (!account) return; // 本地没有用户信息 直接返回(停留在登录页面)
								this.isFocus = false;
								this.isRotate = true;
								this.disabled = true;
								this.account = account;
								this.password = password;
								setTimeout(()=>{this.getUpdate()},1000)
							}
							else 
							{
								if(/02000405/.test(res))
								{
									await uni.showModal({
										content:`NBA账号或者密码错误,请重新输入` ,
										showCancel:false,
									});
									this.NBAUsername = ''
									this.NBAPassword = ''
									uni.removeStorageSync('NBAInfo');
									this.modal = true
								}
								else
								{
									uni.showModal({
										content:res,
										showCancel:false
									}); 
								}
								rejcet(res)
							}
						})
					}
					if (uni.getSystemInfoSync().platform == "ios") 
					{
						let NBAInfo = {
							NBAUsername:this.NBAUsername,
							NBAPassword:this.NBAPassword
						}
						tunnel.connectNBA(NBAInfo,async res=>{
							console.log(res); 
							this.modal = false
							uni.hideLoading()
							if(res == '网关登录成功' || res == '请求权限')
							{
								uni.setStorageSync('NBAInfo',NBAInfo);
								let { account,password } = uni.getStorageSync("userInfo"); // 从本地缓存中同步获取指定 key 对应的内容。
								if (!account) return; // 本地没有用户信息 直接返回(停留在登录页面)
								this.isFocus = false;
								this.isRotate = true;
								this.disabled = true;
								this.account = account;
								this.password = password;
								setTimeout(()=>{this.getUpdate()},1000)
							}
							else 
							{
								if(/用户名或密码错误/.test(res))
								{
									await uni.showModal({
										content:`NBA账号或者密码错误,请重新输入` ,
										showCancel:false,
									});
									this.NBAUsername = ''
									this.NBAPassword = ''
									uni.removeStorageSync('NBAInfo');
									this.modal = true
								}
								else
								{
									uni.showModal({
										title:"NBA登录失败",
										content:res,
										showCancel:false
									}); 
								}
								rejcet(res)
							}
						})
					}
				})
				
				
			},
			// 检查网络状态,并进一步检查APP更新情况(有网条件)
			async getUpdate() {
				let [, netWork] = await uni.getNetworkType()
				if (netWork.networkType == "2g" || netWork.networkType == "none") 
				{
					if (uni.getStorageSync("userInfo"))
						uni.reLaunch({url: "/pages/home/home"}); 
				}	
				else
				{
					console.log(plus.runtime.appid);
					plus.runtime.getProperty(plus.runtime.appid, async widgetInfo => {
						let option = {
							params:{
								appid: 'com.sklgp.warningSystem.ddh',
								version: plus.runtime.version,
								imei: plus.device.imei,
							}
						}
						if (uni.getSystemInfoSync().platform == "android")
							var {data: res} = await this.$http.get('/api/basedata/GetAppUpdateMsg',option)
						if (uni.getSystemInfoSync().platform == "ios")
							var {data: res} = await this.$http.getProxy('/api/basedata/GetAppUpdateMsg',option)
						if (res.data) 
						{
							if (uni.getSystemInfoSync().platform == "android") 
							{
								this.upgradeUrl = res.data.DownLoadURL;
								this.upgradeContent = res.data.Describe || "1.性能优化\n2.修复部分错误"
								this.$refs.yomolUpgrade.show();
							}
							if (uni.getSystemInfoSync().platform == "ios")
							{
								await uni.showModal({
									content: '有新的版本发布,请前往应用商店更新!',
									showCancel:false
								});
							}
						} else 
							uni.reLaunch({url: "/pages/home/home"})
					});
				}
			},
			async startLogin(e) {
				if (this.isRotate) return;
				if (!this.account)
					return uni.showToast({
						title: "账号不能为空!",
						icon: "none"
					}); // 	显示提示框
				if (!this.password)
					return uni.showToast({
						title: "密码不能为空!",
						icon: "none"
					});
				this.isRotate = true; 
				this.disabled = true; 
				let res;
				if (uni.getSystemInfoSync().platform == "android")
				{
					try {
						let data = await this.$http.post("/api/security/token", {
							username: this.account,
							password: this.password,
						});
						res = data.data;
					} catch (e) {
						this.isRotate = false;
						this.disabled = false;
						return;
					}
					let {data: res2} = await this.$http.get("/api/account/GetUserInfo",{
						custom: { auth: false },
						header: { token: res.token }
					});
					let userInfo = {
						account: this.account,
						password: this.password,
						token: res.token
					};
					for (let key in res2.data) {
						userInfo[key] = res2.data[key];
					}
					uni.setStorageSync("userInfo", userInfo); 
					await this.getUpdate()
					this.isRotate = false;
				}
				if (uni.getSystemInfoSync().platform == "ios") 
				{
					tunnel.post({
						url:`${this.$http.config.baseURL}/api/security/token?username=${this.account}&password=${this.password}`,
					},callBack=>{
						callBack = JSON.parse(callBack)
						console.log(callBack);
						//存储token
						if(callBack.status != 0)
						{
							uni.showToast({
								title: callBack.msg,
								icon: 'none'
							});
							this.isRotate = false;
							this.disabled = false;
							return
						}
						tunnel.get({
							url:`${this.$http.config.baseURL}/api/account/GetUserInfo`,
							token:callBack.token
						},callBack2=>{
							callBack2 = JSON.parse(callBack2)
							console.log(callBack2);
							let userInfo = {
								account: this.account,
								password: this.password,
								token: callBack.token
							};
							for (let key in callBack2.data) 
							{
								userInfo[key] = callBack2.data[key];
							}
							console.log(userInfo);
							uni.setStorageSync("userInfo", userInfo); 
							this.getUpdate()
						})	
					})
				}
			},
		},
	};
</script>
复制代码

Una vez completada la escritura, haga clic con el botón derecho en el proyecto UNI: lanzamiento de paquetes locales de aplicaciones nativas: generación de recursos de aplicaciones de paquetes locales

Elimine todo el archivo app/src/main/assets/appsen 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__BCEC007APPIDapps__UNI__BAC0197

Luego ve a app-src-main-assets-data-dcloud_control.xmlmodificarlo appidal que acabas de copiarappid

4.2.4 Prueba 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.jsonDeclare e Moduleintroduzca el complemento nativo a través de
  • Cree un nuevo UNIproyecto 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-ASbajo el proyecto . Agregue lo que desea registrar en el app-src-main-assets/dcloud_uniplugins.jsonnodo moudlesModuleComponent

Luego vaya al appmódulo build.gradlepara 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 21 //建议此属性值设为21 io.dcloud.PandoraEntry 作为apk入口时   必须设置 targetSDKVersion>=21 沉浸式才生效

        versionCode 1
        versionName "1.0"
        multiDexEnabled true
        ndk {
            abiFilters "armeabi-v7a", "x86" //this 货
        }
    }
    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(':NBAModule')
}
复制代码

Haga clic después de completar la configuración runy luego haga clic en el icono en la página de inicio de la aplicación para llamar al método nativo.

Como se puede ver arriba, la llamada se puede hacer normalmente. Prueba de complemento exitosa

Paquete de 5 complementos

El primer paso del paquete de complementos sigue siendo muy simple, haga clic en Gradleel icono en el lado derecho del IDE, busque uniPlugin-Hello-AS/testModule/Tasks/NBATunnel/other/assembleRelease, haga doble clicassembleRelease

En NBATunnel/build/outputs/arrla carpeta, busque nuestro complemento uni-app generado NBATunnel-release.arr de acuerdo con la convención de nomenclatura de complementospackage.json

código específico

{
    "name": "原生插件",
    "id": "NBATunnel",
    "version": "1.0",
    "description": "原生插件",
    "_dp_type":"nativeplugin",
    "_dp_nativeplugin":{
        "android": {
            "plugins": [
                {
                    "type": "module",
                    "name": "NBATunnel",
                    "class": "com.example.NBAmodule.NBATunnel"
                }
            ],
            "hooksClass": "",
            "integrateType": "aar",
            "dependencies": [
            ],
            "compileOptions": {  
                "sourceCompatibility": "1.8",
                "targetCompatibility": "1.8"
            },
            "abis": [
                "armeabi-v7a",
				"x86"
            ],
            "minSdkVersion": "16",
            "useAndroidX": false,  
            "permissions": [
				
            ],
            "parameters": {
                
            }
        }
    }
}
复制代码

Antes de empaquetar, debe recordar manifest.jsonseleccionar el complemento nativo local y encontrará que el nombre del complemento es el campo package.jsonen el archivo name.

Al empaquetar, elija ejecutar: ejecute el teléfono móvil o el emulador, haga una base de depuración personalizada, espere a que se complete el empaque y haga clic para ejecutar, si no hay problema, puede abrir el paquete oficial.

Este artículo se cita del renacuajo sin soporte de Rare Earth Nuggets.

Supongo que te gusta

Origin blog.csdn.net/std7879/article/details/127700402
Recomendado
Clasificación