Skip to content

Commit

Permalink
version 1.3.3
Browse files Browse the repository at this point in the history
  • Loading branch information
syslogic committed Mar 24, 2024
1 parent 1a9c726 commit 8ef32df
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 53 deletions.
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ The official Huawei repositories can be found there: [@HMS-Core](https://github.
---
### Features

- It uploads Android APK/ABB packages to the AppGallery Connect Publishing API.

- It automates the Huawei AppGallery Connect Publishing API.
- It can upload and release Android APK/ABB packages.

### Development

The plugin source code can be swiftly installed into any Android Gradle project with `git clone`:
Expand All @@ -36,15 +37,15 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.3.1'
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
classpath 'io.syslogic:agconnect-publishing-gradle-plugin:1.3.2'
classpath 'io.syslogic:agconnect-publishing-gradle-plugin:1.3.3'
}
}
````

Or in the version-catalog `gradle/libs.versions.toml`:
````toml
[versions]
agconnect_publishing_plugin = '1.3.2'
agconnect_publishing_plugin = '1.3.3'

[plugins]
agconnect_publishing = { id = "io.syslogic.agconnect.publishing", version.ref = "agconnect_publishing_plugin" }
Expand All @@ -55,7 +56,6 @@ Then they can be applied in the module's `build.gradle`:
plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
// id 'io.syslogic.agconnect.publishing'
alias(libs.plugins.agconnect.publishing)
}
Expand All @@ -66,7 +66,7 @@ plugins {
`PublicationExtension` can be configured with the following properties:

- `configFile`: The path to the API client credentials file is absolute.
- `releaseType`: Release Type, 1=network (default), 5=phased.
- `releaseType`: Release Type, 1=network (default), 3=phased.
- `verbose`: Verbose logging, on/off.
- `logHttp`: HTTP logging, on/off.

Expand All @@ -77,8 +77,8 @@ if (rootProject.file(json_agc).exists()) {
agcPublishing {
configFile = rootProject.file(json_agc).absolutePath
releaseType = 1
verbose = false
logHttp = true
verbose = true
}
}
````
Expand Down Expand Up @@ -114,6 +114,18 @@ AAB file someapp_1.0.0-huawei-release.aab has been uploaded.
13.1 MB in 14s equals a transfer-rate of 957.0 kB/s.
````

The log output for task `:mobile:submitReleaseAab` explains what it does.<br/>
To be precise, it submits an <u>already uploaded</u> APK/ABB package for review.

````
> Task :mobile:submitReleaseAab
> POST /api/oauth2/v1/token HTTP/1.1
> HTTP/1.1 200 OK
> POST /api/publish/v2/app-submit?appId=000000000&releaseType=1 HTTP/1.1
> HTTP/1.1 200 OK
Submitted for release: org.acme.someapp (000000000).
````

### Support
- [Documentation](https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-References/agcapi-obtain_token-0000001158365043)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/huawei-developers)
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
plugin_version = '1.3.2'
plugin_version = '1.3.3'
gradle_api = '8.3.1'
gradle_publish = '1.2.1'
gson = '2.10.1'
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/io/syslogic/agconnect/PublishingExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public interface PublishingExtension {
String getConfigFile();

/**
* Release Type
* Release-Type
* <code>agcPublishing { releaseType = 1 }</code>
* @return value 1=network, 5=phased.
* @return value 1=network, 3=phased.
*/
Integer getReleaseType();

Expand All @@ -44,7 +44,7 @@ public interface PublishingExtension {
/**
* Set the Release Type.
* <code>agcPublishing { releaseType = 1 }</code>
* @param value 1=network, 5=phased.
* @param value 1=network, 3=phased.
*/
void setReleaseType(Integer value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public void setConfigFile(@NotNull String value) {
/**
* Release Type.
* <code>agcPublishing { releaseType = 1 }</code>
* @param value 1=network, 5=phased.
* @param value 1=network, 3=phased.
*/
@SuppressWarnings("unused")
public void setReleaseType(@NotNull Integer value) {
if (value == 1 || value == 5) {
if (value == 1 || value == 3) {
this.releaseType = value;
}
}
Expand Down Expand Up @@ -65,9 +65,9 @@ public String getConfigFile() {
}

/**
* Release Type
* Release-Type
* <code>agcPublishing { releaseType = 1 }</code>
* @return value 1=network, 5=phased.
* @return value 1=network, 3=phased.
*/
@Override
public Integer getReleaseType() {
Expand Down
64 changes: 52 additions & 12 deletions src/main/java/io/syslogic/agconnect/PublishingPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.syslogic.agconnect.task.AppInfoTask;
import io.syslogic.agconnect.task.HelpTask;
import io.syslogic.agconnect.task.PublishingTask;
import io.syslogic.agconnect.task.SubmitReleaseTask;
import io.syslogic.agconnect.util.StringUtils;

/**
Expand All @@ -48,7 +49,7 @@ public void apply(@NotNull Project project) {

/* Apply the default path for the API client configuration file. */
this.configFile = project.getRootProject().getProjectDir().getAbsolutePath() +
File.separator + "distribution" + File.separator + "agc-apiclient.json";
File.separator + "distribution" + File.separator + "agconnect_apiclient.json";

/* Project before evaluate: register task `:welp` */
registerHelpTask(project,"welp");
Expand Down Expand Up @@ -89,7 +90,7 @@ public void apply(@NotNull Project project) {
if (appConfigFile != null) {

int releaseType = 1; // 1 is the default and the are only 2 possible values.
if (extension.getReleaseType() != null && extension.getReleaseType() == 5) {
if (extension.getReleaseType() != null && extension.getReleaseType() == 3) {
releaseType = extension.getReleaseType();
}

Expand All @@ -106,21 +107,30 @@ public void apply(@NotNull Project project) {
}
}

/* Register Task: Publish. */
/* Task :publishDebugAab always fails, because the AAB is not signed with the upload key. */
taskName = "publish" + StringUtils.capitalize(artifactType);
if (!artifactType.equals(ArtifactType.AAB) || !buildType.equals("debug")) {
/* Register Tasks: Publish. */
if (verbose) {System.out.println("> " + buildType + " " + artifactType.toUpperCase(Locale.ROOT) + " :" + taskName);}
registerPublishingTask(project, taskName, appConfigFile, artifactType, buildType, null, null, releaseType);
} else if(verbose) {
System.out.println("> " + buildType + " " + artifactType.toUpperCase(Locale.ROOT) + " :" + taskName + " skipped");
}

/* Register Tasks: AppInfo */
/* Register Task: Submit Release */
taskName = "submit" + StringUtils.capitalize(artifactType);
if (! buildType.equals("debug")) {
if (verbose) {System.out.println("> " + buildType + " " + artifactType.toUpperCase(Locale.ROOT) + " :" + taskName);}
registerSubmitReleaseTask(project, taskName, appConfigFile, artifactType, buildType, null, null, releaseType);
} else if(verbose) {
System.out.println("> " + buildType + " " + artifactType.toUpperCase(Locale.ROOT) + " :" + taskName + " skipped");
}

/* Register Task: AppInfo */
taskName = "getAppInfo" + StringUtils.capitalize(buildType);
registerAppInfoTask(project, taskName, appConfigFile, buildType, releaseType);

/* Register Tasks: AppId */
/* Register Task: AppId */
taskName = "getAppId" + StringUtils.capitalize(buildType);
registerAppIdTask(project, taskName, appConfigFile, buildType, releaseType);

Expand Down Expand Up @@ -153,7 +163,7 @@ public void apply(@NotNull Project project) {
if (appConfigFile != null) {

int releaseType = 1; // 1 is the default and the are only 2 possible values.
if (extension.getReleaseType() != null && extension.getReleaseType() == 5) {
if (extension.getReleaseType() != null && extension.getReleaseType() == 3) {
releaseType = extension.getReleaseType();
}

Expand All @@ -176,23 +186,33 @@ public void apply(@NotNull Project project) {
/* Register Tasks: Publish. */
if (verbose) {System.out.println("> " + buildVariant + " " + artifactType.toUpperCase(Locale.ROOT) + " · :" + taskName);}
registerPublishingTask(project, taskName, appConfigFile, artifactType, buildType, buildVariant, productFlavor, releaseType);
} else if(verbose) {
} else if (verbose) {
System.out.println("> " + buildVariant + " " + artifactType.toUpperCase(Locale.ROOT) + " · :" + taskName + " skipped");
}

/* Register Task: Submit Release */
taskName = "submit" + StringUtils.capitalize(buildVariant) + StringUtils.capitalize(artifactType);
if (! buildType.equals("debug")) {
/* Register Tasks: Submit Release. */
if (verbose) {System.out.println("> " + buildVariant + " " + artifactType.toUpperCase(Locale.ROOT) + " · :" + taskName);}
registerSubmitReleaseTask(project, taskName, appConfigFile, artifactType, buildType, buildVariant, productFlavor, releaseType);
} else if (verbose) {
System.out.println("> " + buildVariant + " " + artifactType.toUpperCase(Locale.ROOT) + " · :" + taskName + " skipped");
}

/* Register Tasks: AppId */
/* Register Task: AppId */
taskName = "getAppId" + StringUtils.capitalize(buildType);
registerAppIdTask(project, taskName, appConfigFile, buildType, releaseType);

/* Register Tasks: AppInfo */
/* Register Task: AppInfo */
taskName = "getAppInfo" + StringUtils.capitalize(buildType);
registerAppInfoTask(project, taskName, appConfigFile, buildType, releaseType);

/* Register Tasks: AppInfoBasic */
/* Register Task: AppInfoBasic */
taskName = "updateAppInfoBasic" + StringUtils.capitalize(buildType);
registerAppInfoBasicTask(project, taskName, appConfigFile, buildType, releaseType);

/* Register Tasks: AppInfoLocalized */
/* Register Task: AppInfoLocalized */
taskName = "updateAppInfoLocalization" + StringUtils.capitalize(buildType);
registerAppInfoLocalizationTask(project, taskName, appConfigFile, buildType, releaseType);

Expand Down Expand Up @@ -308,13 +328,33 @@ void registerPublishingTask(
task.getLogHttp().set(logHttp);
task.getVerbose().set(verbose);

/* :publish* tasks depend on :assemble or :bundle tasks; where the name of the build task may vary */
/* :publish* tasks depend on :assemble or :bundle tasks; where the name of the build-task may vary. */
String buildTask = getBuildTask(project, artifactType, buildVariant != null ? buildVariant : buildType);
task.dependsOn(buildTask);
});
}
}

void registerSubmitReleaseTask(
@NotNull Project project, @NotNull String taskName, @NotNull String appConfigFile,
@NotNull String artifactType, @NotNull String buildType,
@Nullable String buildVariant, @Nullable String productFlavor,
@Nullable Integer releaseType
) {
if (project.getTasks().findByName(taskName) == null) {
String apiConfigFile = configFile;
project.getTasks().register(taskName, SubmitReleaseTask.class, task -> {
task.setGroup(taskGroup);
task.getReleaseType().set(releaseType);
task.getApiConfigFile().set(apiConfigFile);
task.getAppConfigFile().set(appConfigFile);
task.getBuildType().set(buildType);
task.getLogHttp().set(logHttp);
task.getVerbose().set(verbose);
});
}
}

/** Obtain Android ApplicationBuildType, which have a ApkSigningConfig. */
@NotNull
String[] getBuildTypes(@NotNull Project project) {
Expand Down
1 change: 0 additions & 1 deletion src/main/java/io/syslogic/agconnect/task/AppIdTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public void run() {
}

/** */
@SuppressWarnings("UnusedReturnValue")
public void getAppIdList() {

HttpGet request = new HttpGet();
Expand Down
35 changes: 17 additions & 18 deletions src/main/java/io/syslogic/agconnect/task/BaseTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import io.syslogic.agconnect.constants.EndpointUrl;
import io.syslogic.agconnect.model.ApiConfigFile;
import io.syslogic.agconnect.model.AppConfigFile;
import io.syslogic.agconnect.model.AppConfigInfo;
import io.syslogic.agconnect.model.TokenRequest;
import io.syslogic.agconnect.model.TokenResponse;

Expand Down Expand Up @@ -74,17 +75,17 @@ abstract public class BaseTask extends DefaultTask {
String ua;
HttpClient client;

Long appId = 0L;
String packageName = null;

String clientId = null;
String clientSecret = null;
String accessToken = null;

String packageName = null;
Long appId = 0L;

/** It sets up HttpClient and parses two JSON config files. */
boolean configure(@NotNull Project project, String appConfig, String apiConfig, Boolean logHttp, Boolean verbose, Integer releaseType) {

if (releaseType != null && releaseType == 5) {
if (releaseType != null && releaseType == 3) {
this.releaseType = releaseType;
}

Expand Down Expand Up @@ -114,23 +115,21 @@ boolean configure(@NotNull Project project, String appConfig, String apiConfig,

file = new File(appConfig);
if (file.exists() && file.canRead()) {

if (verbose) {this.stdOut("App Config: " + appConfig);}
AppConfigFile config = new Gson().fromJson(readFile(file), AppConfigFile.class);
this.appId = config.getAppInfo().getAppId();
this.packageName = config.getAppInfo().getPackageName();
} else {
this.stdErr("AppId not found:");
this.stdErr(file.getAbsolutePath());
return false;
}

/* Log Configuration */
if (verbose) {
this.stdOut(" AppId: " + this.appId);
this.stdOut(" Release: " + (this.releaseType == 1 ? "network":"phased"));
if (this.clientId != null && this.clientSecret != null) {
this.stdOut(" ClientId: " + this.clientId);
this.stdOut(" Secret: " + this.clientSecret);
// TODO: the detection could be improved.
AppConfigInfo item = null;
if (getBuildType().get().equals("release")) {
item = config.getAppInfos().get(0);
} else if (getBuildType().get().equals("debug")) {
item = config.getAppInfos().get(1);
}

if (item != null) {
this.appId = item.getAppId();
this.packageName = item.getPackageName();
}
}
return true;
Expand Down
24 changes: 17 additions & 7 deletions src/main/java/io/syslogic/agconnect/task/PublishingTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import io.syslogic.agconnect.constants.ArtifactType;
import io.syslogic.agconnect.constants.EndpointUrl;
import io.syslogic.agconnect.constants.ErrorMessage;
import io.syslogic.agconnect.constants.ResultCode;
import io.syslogic.agconnect.model.CompilePackageState;
import io.syslogic.agconnect.model.CompileStateResponse;
Expand Down Expand Up @@ -213,6 +214,15 @@ private void updateFileInfo(String fileName, String destFileUrl) {
request.setEntity(entity);

HttpResponse response = this.client.execute(request);
logResponse(fileName, response);

} catch (IOException | URISyntaxException e) {
this.stdErr(e.getMessage());
}
}

private void logResponse(@NotNull String fileName, @NotNull HttpResponse response) {
try {
HttpEntity httpEntity = response.getEntity();
String result = EntityUtils.toString(httpEntity);

Expand All @@ -229,21 +239,21 @@ private void updateFileInfo(String fileName, String destFileUrl) {
String packageIds = String.join(",", Arrays.asList(data.getVersions()));
this.getCompileStatus(packageIds);
}
} else if (
code == ResultCode.ADD_APK_HAS_FAILED &&
message.equals("[cds]add apk failed, additional msg is [app bundle must do app signature.]")
) {
/* Display an error message along with the URL to the relevant console page. */
} else if (code == ResultCode.ADD_APK_HAS_FAILED && message.equals(ErrorMessage.APP_SIGNING_NOT_ENABLED)) {
this.stdErr("Please enable App Signing in order to publish App Bundle format (" + fileName + ").");
this.stdOut("In case the following URL does not lead to the expected package, validate agconnect-services.json.");
this.stdErr("In case the following URL does not lead to the expected package, validate agconnect-services.json.");
this.stdOut(EndpointUrl.AG_CONNECT_CERTIFICATES.replace("{appId}", String.valueOf(this.appId)));
} else if (code == ResultCode.FAILED_TO_UPDATE_PACKAGE && message.equals(ErrorMessage.ONGOING_INTEGRATION_CHECK)) {
this.stdErr("The package may be under review or may already have been released (" + fileName + ").");
this.stdErr("If not released, please cancel the ongoing review if you still wish to update.");
this.stdOut(EndpointUrl.AG_CONNECT_INTEGRATION.replace("{appId}", String.valueOf(this.appId)));
} else {
this.stdErr("\nCode " + code + ": " + message);
}
} else {
this.stdErr(response.getStatusLine().toString());
}
} catch (IOException | URISyntaxException e) {
} catch (IOException e) {
this.stdErr(e.getMessage());
}
}
Expand Down
Loading

0 comments on commit 8ef32df

Please sign in to comment.