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

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 はじめに

  1. セキュアなトンネルの aar によって使用される jar パッケージguava-18.0.jar
  2. セキュアなトンネルの aar によって参照されるサードパーティ プロジェクト
    implementation 'org.bouncycastle:bcprov-jdk15on:1.55'
    implementation 'org.apache.commons:commons-lang3:3.4'
    implementation 'org.slf4j:slf4j-api:1.7.21'
复制代码
  1. セキュア トンネル サーバーのアドレスを構成し、リソース ファイルでセキュア トンネル サーバーのアドレスを構成します。
<string name="client_vpn_server_host">xxx.xxx.xxx.xx:xxxx</string>
复制代码
  1. セキュリティ トンネルが初期化されると、ホワイトリストが自動的に取得され (非同期アクション)、正常に取得された後はローカルに永続化されるため、初めてセキュリティ トンネルを初期化するときは (ネットワーク リクエストのため) 比較的遅くなる可能性があります。 )

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&params2=value2&params3=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 StudioASImport Project

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

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

3.2 プラグインの開発

まず、Android ネイティブ プラグイン開発チュートリアル を段階的に実行してください。JDK のインストールと AS のインストールについては書きませんが、大きな問題はなく、Baidu 上の関連記事であれば実行できます。

公式ノートによると、一般に、ローカルで開発する場合は構成に注意しgradletools.build:gradle ファイル - プロジェクト構造をクリックしてバージョンを表示します。

公式の手順をインストールし、新しい手順を作成します。Moduleその前に、まずプロジェクトの構造をProjectタイプの構造に変換し、ファイル - 新規 - をクリックします。New 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 に問い合わせることができますが、これは単なる警告のようで、結局のところ、私のコンパイル、操作、使用には影響しませんでした。

まず、サードパーティ SDK の構成手順に従って、リソース ファイル (フォルダーの下にあることに注意してください) でセキュア トンネル サーバーのアドレスを構成し、他のモジュールの構成形式を参照して新しい res ファイルを作成mainuniplugin_componentますルゥなど。

今回のネットワークトンネルは Module プラグインモジュールに実装されているので、参考までMXSDK載せておきますModulelibs

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()強制的にActivityinstanceof 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変更しますappidappid

をクリックしrun、アプリのホームページにあるアイコンをクリックしてネイティブ メソッドを呼び出し、logcat入力ログを確認します。

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

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

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

 公式ドキュメントの生成に従って、フォルダー内でプラグインをtestModule-build-outputs-arr見つけます。testModule-release.arruni-app

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

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

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

おすすめ

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