UNI APP---Android ネイティブ プラグイン開発実践 (2)

1 はじめに

最近のプロジェクトでは、製品がネットワーク トンネルを通過し、対応する SDK を提供する必要があります。明らかに、このプロセスはネイティブ開発でのみ実現できます。以前、プロキシ方式によるデータ リクエストについて記事を書きましたが、今回はプロキシ方式によるデータ リクエストについての記事を書きました。Android 側は NBA メソッドを使用してデータをリクエストすることになり、以下でネイティブ プラグインの開発が開始されます。

2. 工具と材料のリスト

道具・材料 バージョン/バージョン名
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

まず、公式のGradel バージョンの注意事項に従って、ご使用の Gradle が要件を満たしているかどうかを確認してください

ASAndroid Gradle Plugin VersionおよびGradle VersionAS 内でFile-Project Structure表示できるもの

3. SDK統合ドキュメント

3.1 はじめに

3.1.1 環境の統合:

  1. libsecure_portal.soライブラリはlibs\armeabiフォルダーの下にのみ配置されます。armeabi-v7a,armeabi64-v8他のディレクトリには配置しないでください。

  2. libsecure_portal.jarファイルは libs ディレクトリに配置されます。

  3. 設定build.gradleファイルに次の設定を追加します

defaultConfig {
    ndk {
            abiFilters 'armeabi'
    }
}

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

复制代码
  1. AndroidMainfest.xml権限を追加します
<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>
复制代码

以上の4ステップが完了すると環境構築は完了です。

3.1.2 コードの統合

1. NBA パラメータを設定し、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. NBA 接続が成功したら、Android システムの NC ネットワーク カードを起動します 注: この関数を初めて呼び出すと、システム認証ボックスがポップアップ表示され、仮想ネットワークの確立を許可するかどうかをユーザーに尋ねます。ここでは「許可」をクリックする必要があります。初めて「辞退」をクリックした場合。アプリをアンインストールし、携帯電話を再起動してからアプリを再インストールする必要があります。そうすると、ユーザーが選択できるように認証ボックスが再びポップアップ表示されます。

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. リライトonActivityResult

@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.開発

4.1 ネイティブプロジェクトの実行

ネイティブプラグインを開発するためには、ネイティブプロジェクトのプロジェクトを構築することが必須条件となりますが、ここでは開発の便宜上、UNI-SDKフォルダ内のプロジェクトを直接使用し、 (以下)UniPlugin-Hello-ASに直接ドラッグして、ファイル - 新規 - をクリックしAndroid StudioASImport Project

を選択した後UniPlugin-Hello-AS、「OK」をクリックすると、ディレクトリ構造全体が表示されます。

ここで、実行ボタンを押してサンプルプロジェクトを開始します。

4.2 プラグインの開発

まず、Android ネイティブ プラグイン開発チュートリアル を段階的に実行してください。公式レイアウトによると、新規作成が完了したら、新しく作成したModule情報を設定する必要があります。公式手順のインストールではないbuild.gradleことに注意して、新規作成します。その前に、まずプロジェクト構造を変換しますタイプの構造に移動し、「ファイル」-「新規作成」-をクリックします。ModuleappModuleProjectNew Module

ライブラリを選択

パッケージ名とModule名前を設定し、「完了」( Finish)をクリックします。

公式のレイアウトによると、新規作成が完了したら、新しく作成したModule情報を設定する必要があります。「はい」と「そうでない」build.gradleに注意してください。Moduleapp

新規作成完了後に以下のエラーメッセージが表示される場合があります

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
复制代码

具体的な解決策は Baidu に問い合わせることができますが、これは単なる警告のようで、結局のところ、私のコンパイル、操作、使用には影響しませんでした。

4.2.1 SDKの構成

サードパーティ SDK の設定手順に従います。

  1. libsecure_portal.soライブラリはlibs\armeabiフォルダーの下にのみ配置されます。armeabi-v7a,armeabi64-v8他のディレクトリには配置しないでください。

  2. libsecure_portal.jarファイルは libs ディレクトリに配置されます。

  1. 設定build.gradleファイルに次の設定を追加します
defaultConfig {
	ndk {
		abiFilters 'armeabi'
	}
}

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

复制代码

上記の設定のNBATunnel module説明に従って、build.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'
}
复制代码

修正後

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')
}
复制代码

NBATunnelモジュールGradle.buildeへのローカルファイルのインポートについてarr、以下の状況をまとめました。

//可以正常的运行,但是打包会出错
//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.xml権限を追加します
<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>
复制代码

環境設定が完了し、以下のビジネスコードが開発されました。

4.2.2 ネイティブコードビジネスの実現

公式の手順によれば、このクラスを継承する必要がありますがUniModule、DEMOの書き方によると詳細は以下の通りです

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 UNI コードの記述

新しい UNI プロジェクトを作成し、ネイティブ プラグインを呼び出すコードを作成します。

<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>
复制代码

書き込みが完了したら、UNI プロジェクトを右クリックします。 release-native APP local package-generate local package APP resource

元のプロジェクトapp/src/main/assets/appsのディレクトリにある__UNI__BCEC007ファイル全体を削除し、APPIDパッケージ化して名前を変更したファイルを、削除したばかりのディレクトリに貼り付けます。apps次に例__UNI__BAC0197を示します。

次に、先ほどコピーしたものにapp-src-main-assets-data-dcloud_control.xml変更しますappidappid

4.2.4 ネイティブ APP でのプラグインのテスト

書き込み後、トンネル初期化テストを実行する必要があります。この呼び出しテストをネイティブ プロジェクトで実装するにはModule、次の手順が必要です。

  • ネイティブ プラグインをdcloud_uniplugins.json宣言してModule導入します。
  • 新しいカスタムUNIプロジェクトを作成し、対応する呼び出しメソッドを作成します。

したがって、最初のステップは、公式ドキュメントの説明に従って、ネイティブ プロジェクトでプラグインを宣言することです:UniPlugin-Hello-ASプロジェクトの下のapp-src-main-assets/dcloud_uniplugins.jsonファイル。moudles登録したいものをノードの下に追加するModuleか、 Component

次に、appモジュールに移動してbuild.gradle、新しい Modle プラグインを追加します

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')
}
复制代码

構成が完了したら をクリックしrun、アプリのホームページにあるアイコンをクリックしてネイティブ メソッドを呼び出します

上記の通り、正常に通話が可能です。プラグインのテストが成功しました

5 プラグインのパッケージ化

プラグインのパッケージ化の最初のステップは非常に簡単です。IDEGradleの右側にあるアイコンをクリックし、 を見つけてuniPlugin-Hello-AS/testModule/Tasks/NBATunnel/other/assembleReleaseダブルクリックします。assembleRelease

NBATunnel/build/outputs/arrフォルダー内で、プラグインの命名規則NBATunnel-release.arr に従って生成された uni-app プラグインを見つけます。package.json

特定のコード

{
    "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": {
                
            }
        }
    }
}
复制代码

パッケージ化する前に、ローカルのネイティブ プラグインを忘れずに選択する必要がありますmanifest.json。プラグイン名が前の .html のフィールドpackage.jsonであることがわかりますname

パッケージ化するとき、実行を選択します - 携帯電話またはエミュレータで実行します - カスタム デバッグ ベースを作成し、パッケージ化が完了するのを待ってクリックして実行します。問題がなければ、公式パッケージを開くことができます

この記事は、レアアースナゲットのサポートされていないオタマジャクシから引用されています。

おすすめ

転載: blog.csdn.net/std7879/article/details/127700402