1 はじめに
最近のプロジェクトでは、製品がネットワーク トンネルを通過し、対応する SDK を提供する必要があります。当然、このプロセスはネイティブ開発でのみ実現できます。著者はネイティブ開発を行ったことも、Java を学んだこともありませんでした。落とし穴がたくさんありました。最終的にタスクを完了するまでに 2 日かかりました。今日、システムは次のステップを要約します。開発は著者のビジネスに基づいているため、手順や詳細は、開発に関連する他の記事とは多少異なる場合があります。ネイティブプラグイン。この記事も弁証法的な心構えで読んでください。
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 |
3. SDK統合ドキュメント
ここでのネイティブ SDK とは、サードパーティ メーカーが提供する SDK を指します。
3.1 はじめに
- セキュアなトンネルの aar によって使用される jar パッケージ
guava-18.0.jar
- セキュアなトンネルの aar によって参照されるサードパーティ プロジェクト
implementation 'org.bouncycastle:bcprov-jdk15on:1.55'
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.slf4j:slf4j-api:1.7.21'
复制代码
- セキュア トンネル サーバーのアドレスを構成し、リソース ファイルでセキュア トンネル サーバーのアドレスを構成します。
<string name="client_vpn_server_host">xxx.xxx.xxx.xx:xxxx</string>
复制代码
- セキュリティ トンネルが初期化されると、ホワイトリストが自動的に取得され (非同期アクション)、正常に取得された後はローカルに永続化されるため、初めてセキュリティ トンネルを初期化するときは (ネットワーク リクエストのため) 比較的遅くなる可能性があります。 )
3.2 統合
安全なトンネルは aar を提供し、必要なドキュメントは aar にパッケージ化されています。メイン プロジェクトの build.gradle ファイルのみが必要です。
dependencies{
...
implementation(name: 'MXSocksCore-x.x.x.xxxxxxxx', ext: 'aar')
...
}
复制代码
xxxxxxxxxxxx はバージョン番号です。自分で変更することもできますが、ファイル名と対応している必要があります。メイン プロジェクトの build.gradle ファイルで aar が参照されていない場合は、メイン プロジェクトの build.gradle ファイルで参照する必要があります。メインファイル
repositories {
flatDir {
dirs 'libs','子工程的libs的相对路径'
}
}
复制代码
の対応する相対パスを変更します。
最後に、プロジェクトの libs フォルダーに aar を置きます
3.3 API
1. トンネルを初期化する
MXAppTunnel.getInstance().initAppTunnel(context, new AppTunnelInitComplete() {
@Override
public void appTunnelInitComplete() {
//初始化完成
}
@Override
public void appTunnelInitError(String msg) {
//初始化失败
}
});
复制代码
使用前にトンネルの初期化を完了する必要があります。このアクションは非同期アクションです。ホワイトリストは最初の起動時に取得され、正常に取得された後にローカルに保存されます。ホワイトリストの取得によって後続の起動がブロックされることはありません。
2. セキュアトンネルログ出力
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. 安全なトンネル情報の出力
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 安全なトンネルの使用
セキュア トンネルは、http および https リクエストに対して手動で設定する必要があるプロキシを使用します。ネットワーク リクエストに対してプロキシを設定する方法は 2 つだけです。プロキシ アドレスは xxx.xxx で、ポートは 3 番目の API で出力されます。
1、HTTPクライアント
HttpHost httpHost = new HttpHost("xxx.x.x.x", xxxx);
httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, httpHost);
复制代码
2、HTTPURL接続
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、HTTPSURL接続
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);
复制代码
注: サンプル コード内のポート xxxx はすべて偽物であり、API の 3 番目の項目に出力された対応するポートを使用する必要があります。
3.5 Demo
このファイルにはMainActivity.java
デモも含まれています
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.開発
3.1 ネイティブプロジェクトの運用
ネイティブプラグインを開発するためには、ネイティブプロジェクトのプロジェクトを構築することが必須条件となりますが、ここでは開発の便宜上、UNI-SDK
フォルダ内のプロジェクトを直接使用し、 (以下)UniPlugin-Hello-AS
に直接ドラッグして、ファイル - 新規 - をクリックし、Android Studio
AS
Import Project
を選択した後UniPlugin-Hello-AS
、「OK」をクリックすると、ディレクトリ構造全体が表示されます。
ここで、実行ボタンを押してサンプルプロジェクトを開始します。
3.2 プラグインの開発
まず、Android ネイティブ プラグイン開発チュートリアル を段階的に実行してください。JDK のインストールと AS のインストールについては書きませんが、大きな問題はなく、Baidu 上の関連記事であれば実行できます。
公式ノートによると、一般に、ローカルで開発する場合は構成に注意しgradle
、tools.build:gradle
ファイル - プロジェクト構造をクリックしてバージョンを表示します。
公式の手順をインストールし、新しい手順を作成します。Module
その前に、まずプロジェクトの構造をProject
タイプの構造に変換し、ファイル - 新規 - をクリックします。New Module
ライブラリを選択
パッケージ名とModule
名前を設定し、「完了」( Finish
)をクリックします。
公式のレイアウトによると、新規作成が完了したら、新しく作成したModule
情報を設定する必要があります。「はい」と「そうでない」build.gradle
に注意してください。Module
app
新規作成完了後に以下のエラーメッセージが表示される場合があります
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 に問い合わせることができますが、これは単なる警告のようで、結局のところ、私のコンパイル、操作、使用には影響しませんでした。
まず、サードパーティ SDK の構成手順に従って、リソース ファイル (フォルダーの下にあることに注意してください) でセキュア トンネル サーバーのアドレスを構成し、他のモジュールの構成形式を参照して新しい res ファイルを作成main
しuniplugin_component
ますルゥなど。
今回のネットワークトンネルは Module プラグインモジュールに実装されているので、参考までにMXSDK
載せておきます。Module
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目录下的模块的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引用的第三方工程结束**/
}
复制代码
アクセスが完了し、run
しばらくすると間違いがないことが分かり、以下のカスタマイズ開発が開始されます。新しいクラスを作成する
公式の手順によれば、このクラスを継承する必要がありますがUniModule
、DEMOの書き方によると詳細は以下の通りです
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);
}
});
}
}
复制代码
ここで、IDE は「シンボルを解決できません」というプロンプトを表示しますMainActivity
これには 「現在のコンテキスト」が関係します。従来の方法によればActivity
、直接統合して、実行コンテキストを取得するためにActivity
書き込むActivity.this
か渡すことができます。getApplicationContext
しかし、公式ドキュメントには次のように書かれています。
Activity
取得方法のこと。mUniSDKInstance.getContext()
強制的にActivity
。instanceof Activity
最初に判断してから強制することをお勧めします。そこで、ここではカプセル化方法を変更し、mUniSDKInstance.getContext()
代替のActivity.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 ネイティブ APP でのプラグインのテスト
書き込み後、トンネル初期化テストを実行する必要があります。この呼び出しテストをネイティブ プロジェクトで実装するにはModule
、次の手順が必要です。
- ネイティブ プラグインを
dcloud_uniplugins.json
宣言してModule
導入します。 - 新しいカスタム
UNI
プロジェクトを作成し、対応する呼び出しメソッドを作成します。
したがって、最初のステップは、公式ドキュメントの説明に従って、ネイティブ プロジェクトでプラグインを宣言することです:UniPlugin-Hello-AS
プロジェクトの下のapp-src-main-assets/dcloud_uniplugins.json
ファイル。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"
}
]
}
]
}
复制代码
次に、app
モジュールに移動してbuild.gradle
、新しい Modle プラグインを追加します
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
でのローカル ファイルのインポートではarr
、次の状況をまとめました
//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'])
复制代码
これに基づいて、この記事ではサードパーティのプラグインを参照するcompileOnly(name: 'MXSocksCore-release_6.8.0_stable_socks_jar_160', ext: 'aar')
方法のみを選択できますarr
。ここでは、サードパーティの arr パッケージのコピーをapp
モジュール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引用的第三方工程结束**/
}
复制代码
次に、新しいUNI
プロジェクトを作成し、ネイティブ プラグインを呼び出すコードを作成します。
書き込みが完了したら、「Publish」→「Native APP Local Packaging」→「Generate Local Packaging APP Resources」をクリックします。
元のプロジェクトapp-src-main-assets-apps
のディレクトリにある__UNI__BCEC007
ファイル全体を削除し、APPID
パッケージ化して名前を変更したファイルを、削除したばかりのディレクトリに貼り付けます。apps
次に例__UNI__911FD69
を示します。
次に、先ほどコピーしたものにapp-src-main-assets-data-dcloud_control.xml
変更しますappid
appid
をクリックしrun
、アプリのホームページにあるアイコンをクリックしてネイティブ メソッドを呼び出し、logcat
入力ログを確認します。
上記の通り、正常に通話が可能です。プラグインのテストが成功しました
3.4 プラグインのパッケージ化
プラグインのパッケージ化の最初のステップは非常に簡単です。IDEGradle
の右側にあるアイコンをクリックし、 を見つけてuniPlugin-Hello-AS-testModule-Tasks-other-assembleRelease
ダブルクリックします。assembleRelease
公式ドキュメントの生成に従って、フォルダー内でプラグインをtestModule-build-outputs-arr
見つけます。testModule-release.arr
uni-app
パッケージ化する前に、ローカルのネイティブ プラグインを忘れずに選択する必要がありますmanifest.json
。プラグイン名が前の .html のフィールドpackage.json
であることがわかりますname
。
パッケージ化するときに、実行 - 携帯電話またはエミュレータで実行 - カスタム デバッグ ベースの作成を選択し、パッケージ化が完了するのを待ってクリックしてこれを実行します
この記事は、レアアースナゲットのサポートされていないオタマジャクシから引用されています。