Skip to content
This repository was archived by the owner on Jun 17, 2024. It is now read-only.

Commit 1e7d129

Browse files
authored
Add sample code for android-publisher API V3.
2 parents 05f7cf2 + a5524f5 commit 1e7d129

17 files changed

+1345
-0
lines changed

v3/java/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.project
2+
.metadata
3+
bin/**
4+
libs/**
5+
src/resources/*.apk
6+
src/resources/*.bak
7+
local.properties
8+
.classpath
9+
.settings/

v3/java/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Google Play Developer API samples
2+
3+
A collection of Java samples for the Play Developer API.
4+
5+
## Installation
6+
7+
1. Download the Google Play Developer API client library:
8+
https://developers.google.com/android-publisher/libraries
9+
10+
2. Unzip the client library. The unzipped folder contains the
11+
google-api-services-androidpublisher-v3.jar client library and a lib/ folder with all required
12+
dependencies.
13+
14+
3. Import the Java sample code into your favorite IDE and reference all libraries in the /lib folder
15+
as well as the google-api-services-androidpublisher-v3.jar from the sample project.
16+
17+
## Getting started
18+
To use the Google Play Developer API you need to create or reuse an existing API project in the
19+
Google Api console, https://console.developers.google.com/. You can either use the API with a client
20+
ID for Native Application (Installed Application) or create a Service Account.
21+
22+
### Edit `ApplicationConfig.java` for global sample configuration
23+
24+
1. Specify the name of your application. If the application name is null or blank, the application
25+
will log a warning. Suggested format is `MyCompany-Application/1.0`.
26+
27+
2. Specify the package name of the app as per developer console.
28+
29+
3. If you want to run any of the upload apk samples, please copy your apk to the `/resources` folder
30+
and specify the apk file path, i.e. `/resources/your_apk.apk`
31+
32+
### First request using OAuth2: Installed application
33+
34+
1. Edit the `/resources/client_secrets.json` file and add the client ID, client secret and redirect
35+
uris.
36+
37+
2. Execute any sample class using its `main()` method to begin the auth flow:
38+
39+
A browser window will open and ask you to login. Make sure the account has
40+
appropriate permissions in the Google Play Developer console.
41+
42+
3. Accept the permissions dialog. The browser should display
43+
44+
`The authentication flow has completed.`
45+
46+
Close the window and go back into your IDE and check the console output.
47+
48+
4. The script will output a list of apks.
49+
50+
5. The tokens will be stored in `.store/android_publisher_api` in your home folder. Remove this file
51+
to restart the auth flow.
52+
53+
54+
### First request using OAuth2: Service accounts
55+
56+
1. Edit `ApplicationConfig.java` and add the service account email
57+
address.
58+
59+
2. Copy the service account key file, generated in the Google APIs Console into
60+
the same directory and rename it to `key.p12`.
61+
62+
3. Execute any sample class using its `main()` method in your IDE
63+
64+
4. The script will output a list of apks.
65+
66+
67+
> You're all set and ready to run the Play Developer API samples.
68+
Thank you for being such a great developer on Google Play, your feedback is very important to ensure
69+
that Google continues to improve the developer experience on Play! Enjoy :-).
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright 2014 Google Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.play.developerapi.samples;
18+
19+
import com.google.api.client.auth.oauth2.Credential;
20+
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
21+
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
22+
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
23+
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
24+
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
25+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
26+
import com.google.api.client.http.HttpTransport;
27+
import com.google.api.client.json.JsonFactory;
28+
import com.google.api.client.json.jackson2.JacksonFactory;
29+
import com.google.api.client.repackaged.com.google.common.base.Preconditions;
30+
import com.google.api.client.repackaged.com.google.common.base.Strings;
31+
import com.google.api.client.util.store.DataStoreFactory;
32+
import com.google.api.client.util.store.FileDataStoreFactory;
33+
import com.google.api.services.androidpublisher.AndroidPublisher;
34+
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
35+
36+
import java.io.File;
37+
import java.io.IOException;
38+
import java.io.InputStreamReader;
39+
import java.security.GeneralSecurityException;
40+
import java.util.Collections;
41+
42+
import javax.annotation.Nullable;
43+
44+
import org.apache.commons.logging.Log;
45+
import org.apache.commons.logging.LogFactory;
46+
47+
/**
48+
* Helper class to initialize the publisher APIs client library.
49+
* <p>
50+
* Before making any calls to the API through the client library you need to
51+
* call the {@link AndroidPublisherHelper#init(String)} method. This will run
52+
* all precondition checks for for client id and secret setup properly in
53+
* resources/client_secrets.json and authorize this client against the API.
54+
* </p>
55+
*/
56+
public class AndroidPublisherHelper {
57+
58+
private static final Log log = LogFactory.getLog(AndroidPublisherHelper.class);
59+
60+
static final String MIME_TYPE_APK = "application/vnd.android.package-archive";
61+
62+
/** Path to the private key file (only used for Service Account auth). */
63+
private static final String SRC_RESOURCES_KEY_P12 = "src/resources/key.p12";
64+
65+
/**
66+
* Path to the client secrets file (only used for Installed Application
67+
* auth).
68+
*/
69+
private static final String RESOURCES_CLIENT_SECRETS_JSON = "/resources/client_secrets.json";
70+
71+
/**
72+
* Directory to store user credentials (only for Installed Application
73+
* auth).
74+
*/
75+
private static final String DATA_STORE_SYSTEM_PROPERTY = "user.home";
76+
private static final String DATA_STORE_FILE = ".store/android_publisher_api";
77+
private static final File DATA_STORE_DIR =
78+
new File(System.getProperty(DATA_STORE_SYSTEM_PROPERTY), DATA_STORE_FILE);
79+
80+
/** Global instance of the JSON factory. */
81+
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
82+
83+
/** Global instance of the HTTP transport. */
84+
private static HttpTransport HTTP_TRANSPORT;
85+
86+
/** Installed application user ID. */
87+
private static final String INST_APP_USER_ID = "user";
88+
89+
/**
90+
* Global instance of the {@link DataStoreFactory}. The best practice is to
91+
* make it a single globally shared instance across your application.
92+
*/
93+
private static FileDataStoreFactory dataStoreFactory;
94+
95+
private static Credential authorizeWithServiceAccount(String serviceAccountEmail)
96+
throws GeneralSecurityException, IOException {
97+
log.info(String.format("Authorizing using Service Account: %s", serviceAccountEmail));
98+
99+
// Build service account credential.
100+
GoogleCredential credential = new GoogleCredential.Builder()
101+
.setTransport(HTTP_TRANSPORT)
102+
.setJsonFactory(JSON_FACTORY)
103+
.setServiceAccountId(serviceAccountEmail)
104+
.setServiceAccountScopes(
105+
Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
106+
.setServiceAccountPrivateKeyFromP12File(new File(SRC_RESOURCES_KEY_P12))
107+
.build();
108+
return credential;
109+
}
110+
111+
/**
112+
* Authorizes the installed application to access user's protected data.
113+
*
114+
* @throws IOException
115+
* @throws GeneralSecurityException
116+
*/
117+
private static Credential authorizeWithInstalledApplication() throws IOException {
118+
log.info("Authorizing using installed application");
119+
120+
// load client secrets
121+
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
122+
JSON_FACTORY,
123+
new InputStreamReader(
124+
AndroidPublisherHelper.class
125+
.getResourceAsStream(RESOURCES_CLIENT_SECRETS_JSON)));
126+
// Ensure file has been filled out.
127+
checkClientSecretsFile(clientSecrets);
128+
129+
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
130+
131+
// set up authorization code flow
132+
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
133+
.Builder(HTTP_TRANSPORT,
134+
JSON_FACTORY, clientSecrets,
135+
Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
136+
.setDataStoreFactory(dataStoreFactory).build();
137+
// authorize
138+
return new AuthorizationCodeInstalledApp(
139+
flow, new LocalServerReceiver()).authorize(INST_APP_USER_ID);
140+
}
141+
142+
/**
143+
* Ensure the client secrets file has been filled out.
144+
*
145+
* @param clientSecrets the GoogleClientSecrets containing data from the
146+
* file
147+
*/
148+
private static void checkClientSecretsFile(GoogleClientSecrets clientSecrets) {
149+
if (clientSecrets.getDetails().getClientId().startsWith("[[INSERT")
150+
|| clientSecrets.getDetails().getClientSecret().startsWith("[[INSERT")) {
151+
log.error("Enter Client ID and Secret from "
152+
+ "APIs console into resources/client_secrets.json.");
153+
System.exit(1);
154+
}
155+
}
156+
157+
/**
158+
* Performs all necessary setup steps for running requests against the API
159+
* using the Installed Application auth method.
160+
*
161+
* @param applicationName the name of the application: com.example.app
162+
* @return the {@Link AndroidPublisher} service
163+
*/
164+
protected static AndroidPublisher init(String applicationName) throws Exception {
165+
return init(applicationName, null);
166+
}
167+
168+
/**
169+
* Performs all necessary setup steps for running requests against the API.
170+
*
171+
* @param applicationName the name of the application: com.example.app
172+
* @param serviceAccountEmail the Service Account Email (empty if using
173+
* installed application)
174+
* @return the {@Link AndroidPublisher} service
175+
* @throws GeneralSecurityException
176+
* @throws IOException
177+
*/
178+
protected static AndroidPublisher init(String applicationName,
179+
@Nullable String serviceAccountEmail) throws IOException, GeneralSecurityException {
180+
Preconditions.checkArgument(!Strings.isNullOrEmpty(applicationName),
181+
"applicationName cannot be null or empty!");
182+
183+
// Authorization.
184+
newTrustedTransport();
185+
Credential credential;
186+
if (serviceAccountEmail == null || serviceAccountEmail.isEmpty()) {
187+
credential = authorizeWithInstalledApplication();
188+
} else {
189+
credential = authorizeWithServiceAccount(serviceAccountEmail);
190+
}
191+
192+
// Set up and return API client.
193+
return new AndroidPublisher.Builder(
194+
HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(applicationName)
195+
.build();
196+
}
197+
198+
private static void newTrustedTransport() throws GeneralSecurityException,
199+
IOException {
200+
if (null == HTTP_TRANSPORT) {
201+
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
202+
}
203+
}
204+
205+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2014 Google Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.play.developerapi.samples;
18+
19+
/**
20+
* Contains global application configuration, which is required by all samples.
21+
*/
22+
public final class ApplicationConfig {
23+
24+
private ApplicationConfig() {
25+
// no instance
26+
}
27+
28+
/**
29+
* Specify the name of your application. If the application name is
30+
* {@code null} or blank, the application will log a warning. Suggested
31+
* format is "MyCompany-Application/1.0".
32+
*/
33+
static final String APPLICATION_NAME = "";
34+
35+
/**
36+
* Specify the package name of the app.
37+
*/
38+
static final String PACKAGE_NAME = "";
39+
40+
/**
41+
* Authentication.
42+
* <p>
43+
* Installed application: Leave this string empty and copy or
44+
* edit resources/client_secrets.json.
45+
* </p>
46+
* <p>
47+
* Service accounts: Enter the service
48+
* account email and add your key.p12 file to the resources directory.
49+
* </p>
50+
*/
51+
static final String SERVICE_ACCOUNT_EMAIL = "";
52+
53+
/**
54+
* Specify the apk file path of the apk to upload, i.e. /resources/your_apk.apk
55+
* <p>
56+
* This needs to be set for running {@link BasicUploadApk} and {@link UploadApkWithListing}
57+
* samples.
58+
* </p>
59+
*/
60+
public static final String APK_FILE_PATH = "";
61+
62+
}

0 commit comments

Comments
 (0)