Gradle 自定义Plugin插件之上传APK到蒲公英

在之前的文章:Gradle 自定义Plugin插件介绍 中,介绍了通过Gradle自定义插件的几种方式。

作为一个的Coder,我们当然不希望我们自定义插件只是简单的打印log啦。比如,之前我们版本开发完成的时候,每次测试的流程都需要手动的打包,加固,上传,钉钉通知等等

现在,我们就通过自定义插件来实现一个打包完成后,自动上传到蒲公英的插件。

首先,在自定义这个插件的时候,我们需要弄明白几个问题。

  • 既然是自动上传,肯定是在打包完的时候上传,那么什么时候打包完成或者说怎么让我们的插件再打包完了以后执行呢?
  • 打包完成后,怎么自动上传?
  • 自动上传肯定需要一些appkey等参数,怎么样传递我们的参数呢?
  • 什么样的包,我们才上传到蒲公英提测呢?

Q1: 什么时候,打包完成?

Gradle的打包,其实也是一组组的Task任务,所以,我们只要在Assemble任务执行完了以后,再执行就可以了。

每个任务都有一个dependsOn()方法。我们只要,让我们的上传任务依赖打包任务就可以了

Q2:打包完成后,怎么自动上传?

我们能自动上传apk,需要提测的地方有公开的API,供我们调用。

这里,我们上传到蒲公英:蒲公英上传文档

通过API,我们就可以实现自动上传了。当然,我们需要传递参数。

Q3:怎么参数传递?

我们知道Project是支持扩展的,我们可以通过

    Extension customExtension = project.getExtensions().create(PLUGIN_EXTENSION_NAME, Extension.class);

把我们自定义的extension的数据类型,作为Project的一个扩展。

然后,在project里面有个回调方法,afterEvaluate(),它就会在构建完成后,执行。我们在这个方法里,来获取,就可以了。

Q4:什么样的包,我们才上传到蒲公英提测呢?

一般需要提测的肯定buildType都是release类型的包。但是,release包可能有一些其他的配置。如果,我们误操作很可能会造成不必要的包上传。

我们可以定义一个新的buidType。比如,uploadRelease?

这样,只有buildType是这个类型的时候,我们才上传,我们的apk。

到这里,我们就清楚了,我们要实现的步骤:

在构建回调里面,我们需要上传Task任务。上传Task任务,需要参数。在Gradle 自定义Plugin插件介绍中,我们使用的是Java语言,这里我们也用Java语言。

我们先定义一个project的扩展。

一、自定义extension扩展

这个里面都是,上传需要的参数,就是一个实体类。

public class Extension {


  public String uKey;
  public String apiKey;
  public String appName;
  public boolean useUpload;
  public Extension(){}


  public Extension(String appName,String uKey,String apiKey){
    this.uKey = uKey;
    this.apiKey = apiKey;
    this.appName = appName;
  }
  public Extension(String appName,String uKey,String apiKey,boolean useUpload){
    this.uKey = uKey;
    this.apiKey = apiKey;
    this.appName = appName;
    this.useUpload = useUpload;
  }

  public static Extension getConfig(Project project) {
    Extension extension = project.getExtensions().findByType(Extension.class);
    if (extension == null) {
      extension = new Extension();
    }
    return extension;
  }

}

这就是一个简单的model类。主要有上传到蒲公英需要的uKey,apiKey等等

二、自定义任务,上传apk

有了上传的参数,我们就可以创建我们上传的任务了。

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() {
    for (BaseVariantOutput output : mVariant.getOutputs()) {
      File file = output.getOutputFile();
      if (file == null || !file.exists()) {
        throw new GradleException("apk file is not exist!");
      }
      Extension extension = Extension.getConfig(mTargetProject);

      PGYRequest request = new PGYRequest();
      request.apiKey = extension.apiKey;
      request.uKey = extension.uKey;
      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);
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {

    }
  }
}

这里,可以看出,我们就是使用OKHttp来调用api上传apk的。
并且通过upload result打印上传返回的结果。

添加了@TaskAction的注解后,我们的方法就会被执行。

通过BaseVariantOutput 获取apk的输入路径。通过Extension来获取要上传的参数信息。通过upload(),把我们的apk及需要的参数上传到蒲公英。

有了任务,下面,就是创建插件跟任务绑定。

三、创建我们要上传的插件Plugin

我们实现Plugin,然后,在apply()方法里,监听project.afterEvaluate()回调。

public class TestJavaPlugin implements Plugin<Project> {
  //project的扩展名字
  public static final String PLUGIN_EXTENSION_NAME = "uploadHelperJava";
  public static final String ANDROID_EXTENSION_NAME = "android";

  @Override
  public void apply(Project project) {
	//创建project的扩展
    Extension customExtension = 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) {
			//只监听buildType是uploadRelease的包
          if (variant.getBuildType().getName().equalsIgnoreCase("uploadRelease") ) {
            String variantName =
                variant.getName().substring(0, 1).toUpperCase() + variant.getName().substring(1);
			//创建我们,上传到蒲公英的task任务
            PGYUploadTask uploadTask = project.getTasks()
                .create("uploadJavaFor" + variantName, PGYUploadTask.class);
            uploadTask.init(variant, project);


            //依赖关系 。上传依赖打包,打包依赖clean。
            variant.getAssembleProvider().get().dependsOn(project.getTasks().findByName("clean"));
            uploadTask.dependsOn(variant.getAssembleProvider().get());
          }
        }
      }
    });
  }
}

这里,我们首先创建了Exension的扩展,然后,判断buildType,是否是我们要上传的type。最后,就是让我们的上传任务依赖打包任务,这样就做到了先打包后上传。

四、项目引用插件

项目下的build.gradle,引入插件

buildscript {
    repositories {
        google()
        jcenter()
        maven{
            url uri('./repo/')
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.1'

        classpath 'com.liu.alone.plugin:java-plugin:1.0.0'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

我们把发布的插件,放到了repo目录下,让其引入。

app module使用插件及配置buildType

android{
	...
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.release
            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 = "testGradle"

    uKey = "c9d2625c0cf221d8f4a98738f4c05e9a"

    apiKey = "fac8875534d045a2be3f229abd46cc3e"
}

如果,buildType里面设置了跟构建无关的东西的话。最好,还是添加一个独立的buildType,当然,这个不是必须的。

五、执行

执行,我们插件uploadhelerjava下面的uploadJavaForUploadRelease任务。
在这里插入图片描述

执行结果


> Task :app:packageUploadRelease
> Task :app:assembleUploadRelease

> Task :app:uploadJavaForUploadRelease
WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration-avoidance.
To determine what is calling variantOutput.getPackageApplication(), use -Pandroid.debug.obsoleteApi=true on the command line to display a stack trace.
upload result: {"code":0,"message":"","data":{"appKey":"c5a8638d37251c8410ef476615ae9a8e","userKey":"c9d2625c0cf221d8f4a98738f4c05e9a","appType":"2","appIsLastest":"2","appFileSize":"169960","appName":"ObjectAnimatorTest","appVersion":"1.0","appVersionNo":"1","appBuildVersion":"6","appIdentifier":"com.liu.objectanimatortest","appIcon":"c2e1b68bbeda5d500f3f90fb9213512b","appDescription":"","appUpdateDescription":"","appScreenshots":"","appShortcutUrl":"t6rG","appCreated":"2019-12-28 13:08:14","appUpdated":"2019-12-28 13:08:14","appQRCodeURL":"http:\/\/www.pgyer.com\/app\/qrcodeHistory\/45111fcbd38c3951c823007bbc33a007e1147a6f442e81200235c6899ba4ea87"}}

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/4.10.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 28s

可以看到,上传成功后,返回的信息upload result已经显示出来。

六、其他的文件

其他的文件跟Gradle 自定义Plugin插件介绍 中的一样。这里贴下代码。

插件的结构,跟properties内容

在这里插入图片描述

插件的build.gradle

这个里面,因为涉及到了联网上传,添加了okhttp。

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

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值