Gradle カスタム プラグイン Dingding 通知の送信

前回の記事ではGradleプラグインの使い方、apk強化、Dandelionへのアップロード方法を紹介しました。

この記事は主に、Gradle プラグインを使用してプロセスをさらに改善し、パッケージ化 - 強化 - タンポポのアップロード - DingTalk メッセージの送信を実現し、完全な自動化を実現することを目的としています。

前回の記事の紹介:

Gradleカスタムプラグインの紹介

Gradle カスタム プラグイン APK を Dandelion にアップロード

Gradle カスタム プラグイン 360 の強化

次に、DingTalk 通知を送信する簡単なプロセスを見てみましょう。

  • DingTalk ロボットを作成します。メッセージを送信するための資格情報を取得します。
  • 認証情報とDingTalkで必要なデータ形式に従ってAPIを呼び出します。

DingTalk の API ドキュメントには詳細なプロセスの説明が含まれているため、ここでは詳しく説明しません。

DingTalk メッセージ タスクの開発タスク フロー:

1. DingTalk ロボットを作成する

DingTalk メッセージを送信するには、DingTalk グループに DingTalk ボットを作成する必要があります。DingTalk ロボットを作成したら、ロボットの Webhook とシークレットを介して DingTalk グループにメッセージを送信します。

1.「グループスマートグループアシスタント」をクリックします。

ここに画像の説明を挿入

2. 「ロボットの作成」をクリックします。

クリックしてロボットを追加します (許可が必要な場合があります)。これにはコンピューターの操作が必要です。ロボットの作成後、Webhook とシークレットを取得します。
これら 2 つのパラメータは、データを送信するために必要なものです。

ここに画像の説明を挿入
ロボットを作成した後、DingTalk メッセージを送信するための資格情報である Webhook とシークレットを取得しました。
ここに画像の説明を挿入

ロボットを作成した後、DingTalk の API ドキュメントに従って資格情報を介して API を呼び出すことができます。ここでは公式の SDK を使用せず、ドキュメントの形式に従って OKHttp 経由でメッセージを送信します。

2. DingTalk メッセージを送信するための Task タスクを作成する

ドキュメントによると、DingTalk を送信するには、パラメータwebhook、secretを渡す必要があることがわかっています。
次に、送信するメッセージのタイプに応じてさまざまなパラメーターを選択します。ここでは、リンク タイプを使用してメッセージを送信します。

{
    "msgtype": "link", 
    "link": {
        "text": "这个即将发布的新版本,创始人xx称它为“红树林”。
而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是“红树林”?", 
        "title": "时代的火车向前开", 
        "picUrl": "", 
        "messageUrl": "https://www.dingtalk.com/s?__biz=MzA4NjMwMTA2Ng==&mid=2650316842&idx=1&sn=60da3ea2b29f1dcc43a7c8e4a7c97a16&scene=2&srcid=09189AnRJEdIiWVaKltFzNTw&from=timeline&isappinstalled=0&key=&ascene=2&uin=&devicetype=android-23&version=26031933&nettype=WIFI"
    }
}

ここでは、text、title、picUrl、messageUrlをアップロードする必要があることがわかります。4つのパラメータ
picUrl、link messageUrl は、Dandelion にアップロードした後に取得する必要があります。

この場合、Webhook、secret、text、titleの 4 つのパラメーターを追加する拡張機能が必要です。他の 2 つのパラメーター (picUrl、messageUrl) は、Dandelion を正常にアップロードした後に取得する必要があります。

上記のパラメータの準備ができたら、OKHttp を介して API を呼び出すだけで完了します。

準備には次のものが含まれます。

  • DingTalk のニーズを満たす Model クラスを構築する
  • 拡張機能にパラメーターを追加します (上記で分析した 4 つのパラメーター)
  • Dandelion のアップロードに成功したら、Url パラメータを取得します
  • 拡張機能のパラメータの解析
  • API を呼び出して DingTalk メッセージを送信する

1. DingTalk のニーズを満たす Model クラスを構築する

DingTalk の送信は Json を通じて配信されます。最初に必要なモデルを構築します

public static class DingTalkModel {

        public String picUrl;
        public String messageUrl;
        public String title;
        public String text;
    }

    public static class DingTalkRequest {

        public String msgtype = "link";
        public DingTalkModel link;

        public DingTalkRequest(DingTalkModel link) {
            this.link = link;
        }
    }

2. 拡張機能にパラメータを追加する

ここには主に 4 つのパラメータがあります: アップロード認証情報 (Webhook とシークレット)、送信メッセージ パラメータ (タイトル、コンテンツ)。

Extensionクラスにパラメータを追加します。

public class Extension {


  public String uKey;
  public String apiKey;
  public String appName;

  //==========加固相关的信息
//指向加固的jar包
  public File reinforceJarFile;
  //登陆用户名
  public String reinforceUsername;
  //登陆密码
  public String reinforcePassword;
  //输出apk的目录
  public File outputFile;

  //dingding
  public String dingWebhook;
  public String dingSecret;
  public String title;
  public String content;

  public Extension() {
  }

  public Extension(String uKey, String apiKey, String appName, File reinforceJarFile,
      String reinforceUsername, String reinforcePassword, File outputFile,
      String dingWebhook, String dingSecret, String title, String content) {
    this.uKey = uKey;
    this.apiKey = apiKey;
    this.appName = appName;
    this.reinforceJarFile = reinforceJarFile;
    this.reinforceUsername = reinforceUsername;
    this.reinforcePassword = reinforcePassword;
    this.outputFile = outputFile;
    this.dingWebhook = dingWebhook;
    this.dingSecret = dingSecret;
    this.title = title;
    this.content = content;
  }

  public Extension(String uKey, String apiKey, String appName, File reinforceJarFile,
      String reinforceUsername, String reinforcePassword, File outputFile) {
    this.uKey = uKey;
    this.apiKey = apiKey;
    this.appName = appName;
    this.reinforceJarFile = reinforceJarFile;
    this.reinforceUsername = reinforceUsername;
    this.reinforcePassword = reinforcePassword;
    this.outputFile = outputFile;
  }
  public Extension(String appName, String uKey, String apiKey) {
    this.uKey = uKey;
    this.apiKey = apiKey;
    this.appName = appName;
  }
  public static Extension getConfig(Project project) {
    Extension extension = project.getExtensions().findByType(Extension.class);
    if (extension == null) {
      extension = new Extension();
    }
    return extension;
  }

}


3. Dandelion のアップロードが成功したら、Url パラメータを取得します

DingTalk タスクで静的プロパティを定義します。Dandelion アップロード タスクが完了したら、setData() メソッドを呼び出してパラメータを渡します。

public class DingTalkTask extends DefaultTask {

    private static String sShotcutUrl, sQRCodeURL;
	...

    public static void setData(String shortcutUrl, String qrUrl) {
        sShotcutUrl = shortcutUrl;
        sQRCodeURL = qrUrl;
    }
}

4. 拡張機能のパラメータを解析する

ここではネットワーク化前のパラメータの準備ですが、ここで必要なパラメータを解析してモデル クラスに入れる必要があります。

   private DingTalkModel initModel() {
        DingTalkModel model = new DingTalkModel();
        model.picUrl = sQRCodeURL;
        model.messageUrl = "http://www.pgyer.com/" + sShotcutUrl;
        Extension extension =Extension.getConfig(mTargetProject);
        model.title = extension.title;
        model.text = extension.content;

        mWebhook = extension.dingWebhook;
        mSecret = extension.dingSecret;
        return model;
    }

ここで DingTalk に必要なモデルを作成し、対応するすべてのパラメーターを取得します。

5. APIを呼び出してDingTalkメッセージを送信します

これは、OKHttp を使用して直接呼び出します


    @TaskAction
    public void sendDingtalk() {
        DingTalkModel model = initModel();

        String url = createDingUrl();

        OkHttpClient okHttpClient = new OkHttpClient();
        Gson gson = new Gson();
        String json = gson.toJson(new DingTalkRequest(model));
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8")
            , json);
        Request request = new Request.Builder()
            .url(url)
            .post(requestBody)
            .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            System.out.println("send message result: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * create dingtalk  url
     */
    private String createDingUrl() {
        Long timestamp = System.currentTimeMillis();
        return mWebhook + "&timestamp=" + timestamp + "&sign=" + createSign(timestamp, mSecret);
    }

   private String createSign(Long timestamp, String secret) {
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


この時点で、DingTalk タスクが作成されます。完全なコードを投稿してください。


public class DingTalkTask extends DefaultTask {

    private static String sShotcutUrl, sQRCodeURL;
    private BaseVariant mVariant;
    private Project mTargetProject;

    private String mWebhook;
    private String mSecret;

    public static class DingTalkModel {

        public String picUrl;
        public String messageUrl;
        public String title;
        public String text;
    }

    public static class DingTalkRequest {

        public String msgtype = "link";
        public DingTalkModel link;

        public DingTalkRequest(DingTalkModel link) {
            this.link = link;
        }
    }

    public void init(BaseVariant variant, Project project) {
        this.mVariant = variant;
        this.mTargetProject = project;
        setDescription("send message to ding talk");
        setGroup(TestJavaPlugin.PLUGIN_EXTENSION_NAME);
    }

    @TaskAction
    public void sendDingtalk() {
        DingTalkModel model = initModel();

        String url = createDingUrl();

        OkHttpClient okHttpClient = new OkHttpClient();
        Gson gson = new Gson();
        String json = gson.toJson(new DingTalkRequest(model));
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8")
            , json);
        Request request = new Request.Builder()
            .url(url)
            .post(requestBody)
            .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            System.out.println("send message result: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * create dingtalk  url
     */
    private String createDingUrl() {
        Long timestamp = System.currentTimeMillis();
        return mWebhook + "&timestamp=" + timestamp + "&sign=" + createSign(timestamp, mSecret);
    }

    private DingTalkModel initModel() {
        DingTalkModel model = new DingTalkModel();
        model.picUrl = sQRCodeURL;
        model.messageUrl = "http://www.pgyer.com/" + sShotcutUrl;
        Extension extension =Extension.getConfig(mTargetProject);
        model.title = extension.title;
        model.text = extension.content;

        mWebhook = extension.dingWebhook;
        mSecret = extension.dingSecret;
        return model;
    }

    private String createSign(Long timestamp, String secret) {
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static void setData(String shortcutUrl, String qrUrl) {
        sShotcutUrl = shortcutUrl;
        sQRCodeURL = qrUrl;
    }
}

3. Dandelion Task タスクを変更してアップロードします

上で述べたように、アップロードが完了したら、URL を DingTalk タスク タスクに渡す必要があります。

public class PGYUploadTask extends DefaultTask {

    private BaseVariant mVariant;
    private Project mTargetProject;

    public static class PGYRequest {

        public String uKey;
        public String apiKey;
        //1,install by public 2,install by password 3,install by invite
        public String installType;
    }

    public void init(BaseVariant variant, Project project) {
        this.mVariant = variant;
        this.mTargetProject = project;
        setDescription("upload to pgy");
        setGroup(TestJavaPlugin.PLUGIN_EXTENSION_NAME);
    }

    @TaskAction
    public void uploadToPGY() {
        Extension extension = Extension.getConfig(mTargetProject);

        PGYRequest request = new PGYRequest();
        request.apiKey = extension.apiKey;
        request.uKey = extension.uKey;
        File apkDir = extension.outputFile;
        if (apkDir == null || !apkDir.exists()) {
            upload(request);
        } else {
            File[] files = apkDir.listFiles();
            if (files != null && files.length > 0) {
                upload(request.uKey, request.apiKey, files[0]);
            } else {
                upload(request);
            }
        }
    }

    private void upload(PGYRequest request) {
        for (BaseVariantOutput output : mVariant.getOutputs()) {
            File file = output.getOutputFile();
            if (file == null || !file.exists()) {
                throw new GradleException("apk file is not exist!");
            }
            upload(request.uKey, request.apiKey, file);
        }
    }

    private void upload(String ukey, String apiKey, File apkFile) {
        //builder
        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        //add part
        bodyBuilder.addFormDataPart("uKey", ukey);
        bodyBuilder.addFormDataPart("_api_key", apiKey);
        //add file
        bodyBuilder.addFormDataPart("file", apkFile.getName(), RequestBody
            .create(MediaType.parse("*/*"), apkFile));

        //request

        Request request = new Request.Builder()
            .url("http://upload.pgyer.com/apiv1/app/upload")
            .post(bodyBuilder.build())
            .build();

        OkHttpClient client = new OkHttpClient();
        try {
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            System.out.println("upload result: " + result);
            parseResult(result);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void parseResult(String result) {
        if (result == null || result.length() == 0) {
            throw new IllegalArgumentException("upload apk to PGY failed");
        }
        PGYResonpse data = new Gson().fromJson(result, PGYResonpse.class);
        if (data == null || data.code != 0) {
            throw new IllegalArgumentException("upload apk to PGY failed");
        }
        DingTalkTask.setData(data.data.appShortcutUrl, data.data.appQRCodeURL);
    }

    public static class PGYResonpse {

        public int code;
        public String message;
        public PGYDetail data;

        public static class PGYDetail {

            public String appShortcutUrl;
            public String appUpdated;
            public String appQRCodeURL;
            public String appVersion;
            public String appVersionNo;
            public String appIcon;

        }
    }

}

ここでは、まず Dandelion によって返される結果の Model クラスを作成し、アップロードされた Dandelion 結果を取得した後、DingTalkTask.setData() メソッドを通じてデータを DingTalk Task タスクに渡します。

4 番目に、Plugin プラグイン内のタスクの依存関係を変更します。

ここでは主に、Plugin プラグイン内のタスクの依存関係を変更します。DingTalk のタスクを Dandelion のアップロード タスクに依存させ、アップロードが成功した後に DingTalk 通知が送信されるようにします。

public class TestJavaPlugin implements Plugin<Project> {

    public static final String PLUGIN_EXTENSION_NAME = "uploadHelperJava";
    public static final String ANDROID_EXTENSION_NAME = "android";


    @Override
    public void apply(Project project) {
        project.getExtensions()
            .create(PLUGIN_EXTENSION_NAME, Extension.class);
        //项目编译完成后,回调
        project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                DomainObjectSet<ApplicationVariant> appVariants = ((AppExtension) project
                    .getExtensions().findByName(ANDROID_EXTENSION_NAME)).getApplicationVariants();
                for (ApplicationVariant variant : appVariants) {
                    //release apk
                    if (variant.getBuildType().getName().equalsIgnoreCase("uploadRelease")) {
                        String variantName =
                            variant.getName().substring(0, 1).toUpperCase() + variant.getName()
                                .substring(1);

                        //create task
                        ReinforceTask reinforceTask = project.getTasks()
                            .create("reinforceFor" + variantName, ReinforceTask.class);
                        reinforceTask.init(variant, project);

                        PGYUploadTask uploadTask = project.getTasks()
                            .create("uploadJavaFor" + variantName, PGYUploadTask.class);
                        uploadTask.init(variant, project);

                        DingTalkTask talkTask = project.getTasks()
                            .create("dingTalkFor" + variantName, DingTalkTask.class);
                        talkTask.init(variant, project);

                        //depend on
                        variant.getAssembleProvider().get()
                            .dependsOn(project.getTasks().findByName("clean"));
                        reinforceTask.dependsOn(variant.getAssembleProvider().get());
                        uploadTask.dependsOn(reinforceTask);
                        talkTask.dependsOn(uploadTask);

                    }
                }
            }
        });
    }
}

ここでは、DingTalk タスクも作成しました。その後、依存関係が変更されました。この時点で、パッケージ化 – 強化 – Dandelion のアップロード – DingTalk 通知の送信というプロセス全体が完了しました。

5、電話してください

プラグインのリリースや導入については以前の記事(冒頭にリンクあり)で触れているのでここでは書きません。

プラグインを呼び出す必要があるアプリのモジュールの下にある build.gradle を見てみましょう。

apply plugin: 'com.android.application'

android {
    ......
    signingConfigs {
        release {
            storeFile file('xxx.jks')
            storePassword "xxx"
            keyAlias "xxx"
            keyPassword "xxx"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        uploadRelease {
            minifyEnabled false
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

......

apply plugin: 'com.liu.alone.plugin'
uploadHelperJava {
    appName = "测试APP"

    uKey = "xxxx"

    apiKey = "xxxx"

    //加固相关的信息
    reinforceJarFile = file("../libs/jiagu.jar")
    reinforceUsername = "18032793516"
    reinforcePassword = "san7758521"
    outputFile = file("${buildDir.getAbsolutePath()}\\jiagu")

    //钉钉,这里需要修改成自己的值
    dingWebhook = "https://oapi.dingtalk.com/robot/send?access_token=xxx"
    dingSecret= "xxx"
    title = "新版本APP上传完成"
    content="体验新版本APP,请到蒲公英下载"

}


タスク呼び出し:

ここに画像の説明を挿入

印刷結果:

> Task :app:reinforceForUploadRelease
==============start JiaGu
....
任务完成_已签名


> Task :app:uploadJavaForUploadRelease
upload result: {"code":0,"message":"","data":{"appKey":"3e95fe0e7fa74e9f7a310bbdfbd139cc","userKey":"c9d2625c0cf221d8f4a98738f4c05e9a","appType":"2","appIsLastest":"2","appFileSize":"3264349","appName":"PluginTest","appVersion":"1.0","appVersionNo":"1","appBuildVersion":"4","appIdentifier":"com.liu.plugintest","appIcon":"9664daaa8a725f726bcb6018495f14a7","appDescription":"","appUpdateDescription":"","appScreenshots":"","appShortcutUrl":"DqmH","appCreated":"2020-01-03 12:21:24","appUpdated":"2020-01-03 12:21:24","appQRCodeURL":"http:\/\/www.pgyer.com\/app\/qrcodeHistory\/9c27fd62288ce774fafb622d8f6df0bbcd9f90cf0b9ba39846c1c6864c93b135"}}

> Task :app:dingTalkForUploadRelease
send message result: {"errcode":0,"errmsg":"ok"}

ここでは、3 つのタスクが連続して実行されたことがわかります: Task :app:reinforceForUploadRelease、Task :app:uploadJavaForUploadRelease、Task :app:dingTalkForUploadRelease

最後にDingTalk通知
ここに画像の説明を挿入

この時点で、リリースのテストの自動化プロセス全体 (パッケージ化、強化、Dandelion のアップロード、DingTalk 通知の送信) は、 Gradle プラグインをカスタマイズすることによって実現されます。

その他の書類

プラグイン-ビルド.gradle

apply plugin: 'java-library'
apply plugin: 'maven'
dependencies {
    compile gradleApi()
    compile localGroovy()
    compile 'com.android.tools.build:gradle:3.3.1'
    implementation("com.squareup.okhttp3:okhttp:3.8.1")
}
repositories {
    mavenCentral()

}

group = 'com.liu.alone.plugin'
version = '1.0.0'
archivesBaseName = 'java-plugin'
//
//upload
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../repo'))
        }
    }
}

おすすめ

転載: blog.csdn.net/ecliujianbo/article/details/103818432