├── LICENSE └── v3 ├── java ├── .gitignore ├── README.md └── src │ ├── com │ └── google │ │ └── play │ │ └── developerapi │ │ └── samples │ │ ├── AndroidPublisherHelper.java │ │ ├── ApplicationConfig.java │ │ ├── BasicUploadApk.java │ │ ├── ListApks.java │ │ ├── UpdateListing.java │ │ └── UploadApkWithListing.java │ └── resources │ └── client_secrets.json └── python ├── README.md ├── basic_list_apks.py ├── basic_list_apks_service_account.py ├── basic_upload_apks.py ├── client_secrets.json ├── update_listings.py ├── upload_apks_rollout.py └── upload_apks_with_listing.py /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2014 Google Inc. 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /v3/java/.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .metadata 3 | bin/** 4 | libs/** 5 | src/resources/*.apk 6 | src/resources/*.bak 7 | local.properties 8 | .classpath 9 | .settings/ 10 | -------------------------------------------------------------------------------- /v3/java/README.md: -------------------------------------------------------------------------------- 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 :-). 70 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/AndroidPublisherHelper.java: -------------------------------------------------------------------------------- 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 | *

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 | *

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 | } 206 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/ApplicationConfig.java: -------------------------------------------------------------------------------- 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 | *

43 | * Installed application: Leave this string empty and copy or 44 | * edit resources/client_secrets.json. 45 | *

46 | *

47 | * Service accounts: Enter the service 48 | * account email and add your key.p12 file to the resources directory. 49 | *

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 | *

56 | * This needs to be set for running {@link BasicUploadApk} and {@link UploadApkWithListing} 57 | * samples. 58 | *

59 | */ 60 | public static final String APK_FILE_PATH = ""; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/BasicUploadApk.java: -------------------------------------------------------------------------------- 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.util.Lists; 20 | import com.google.api.services.androidpublisher.model.LocalizedText; 21 | import com.google.api.services.androidpublisher.model.TrackRelease; 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.net.URISyntaxException; 25 | import java.security.GeneralSecurityException; 26 | import java.util.ArrayList; 27 | import java.util.Collections; 28 | import java.util.List; 29 | 30 | import org.apache.commons.logging.Log; 31 | import org.apache.commons.logging.LogFactory; 32 | 33 | import com.google.api.client.http.AbstractInputStreamContent; 34 | import com.google.api.client.http.FileContent; 35 | import com.google.api.client.repackaged.com.google.common.base.Preconditions; 36 | import com.google.api.client.repackaged.com.google.common.base.Strings; 37 | import com.google.api.services.androidpublisher.AndroidPublisher; 38 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits; 39 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Apks.Upload; 40 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Commit; 41 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Insert; 42 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Tracks.Update; 43 | import com.google.api.services.androidpublisher.model.Apk; 44 | import com.google.api.services.androidpublisher.model.AppEdit; 45 | import com.google.api.services.androidpublisher.model.Track; 46 | 47 | /** 48 | * Uploads an apk to the alpha track. 49 | */ 50 | public class BasicUploadApk { 51 | 52 | private static final Log log = LogFactory.getLog(BasicUploadApk.class); 53 | 54 | /** 55 | * Track for uploading the apk, can be 'alpha', beta', 'production' or 56 | * 'rollout'. 57 | */ 58 | private static final String TRACK_ALPHA = "alpha"; 59 | 60 | public static void main(String[] args) { 61 | try { 62 | Preconditions.checkArgument(!Strings.isNullOrEmpty(ApplicationConfig.PACKAGE_NAME), 63 | "ApplicationConfig.PACKAGE_NAME cannot be null or empty!"); 64 | 65 | // Create the API service. 66 | AndroidPublisher service = AndroidPublisherHelper.init( 67 | ApplicationConfig.APPLICATION_NAME, ApplicationConfig.SERVICE_ACCOUNT_EMAIL); 68 | final Edits edits = service.edits(); 69 | 70 | // Create a new edit to make changes to your listing. 71 | Insert editRequest = edits 72 | .insert(ApplicationConfig.PACKAGE_NAME, 73 | null /** no content */); 74 | AppEdit edit = editRequest.execute(); 75 | final String editId = edit.getId(); 76 | log.info(String.format("Created edit with id: %s", editId)); 77 | 78 | // Upload new apk to developer console 79 | final String apkPath = BasicUploadApk.class 80 | .getResource(ApplicationConfig.APK_FILE_PATH) 81 | .toURI().getPath(); 82 | final AbstractInputStreamContent apkFile = 83 | new FileContent(AndroidPublisherHelper.MIME_TYPE_APK, new File(apkPath)); 84 | Upload uploadRequest = edits 85 | .apks() 86 | .upload(ApplicationConfig.PACKAGE_NAME, 87 | editId, 88 | apkFile); 89 | Apk apk = uploadRequest.execute(); 90 | log.info(String.format("Version code %d has been uploaded", 91 | apk.getVersionCode())); 92 | 93 | // Assign apk to alpha track. 94 | List apkVersionCodes = new ArrayList<>(); 95 | apkVersionCodes.add(Long.valueOf(apk.getVersionCode())); 96 | Update updateTrackRequest = edits 97 | .tracks() 98 | .update(ApplicationConfig.PACKAGE_NAME, 99 | editId, 100 | TRACK_ALPHA, 101 | new Track().setReleases( 102 | Collections.singletonList( 103 | new TrackRelease() 104 | .setName("My Alpha Release") 105 | .setVersionCodes(apkVersionCodes) 106 | .setStatus("completed") 107 | .setReleaseNotes(Collections.singletonList( 108 | new LocalizedText() 109 | .setLanguage("en-US") 110 | .setText("Adds the exciting new feature X!")))))); 111 | Track updatedTrack = updateTrackRequest.execute(); 112 | log.info(String.format("Track %s has been updated.", updatedTrack.getTrack())); 113 | 114 | // Commit changes for edit. 115 | Commit commitRequest = edits.commit(ApplicationConfig.PACKAGE_NAME, editId); 116 | AppEdit appEdit = commitRequest.execute(); 117 | log.info(String.format("App edit with id %s has been comitted", appEdit.getId())); 118 | 119 | } catch (IOException | URISyntaxException | GeneralSecurityException ex) { 120 | log.error("Excpetion was thrown while uploading apk to alpha track", ex); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/ListApks.java: -------------------------------------------------------------------------------- 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 java.io.IOException; 20 | import java.security.GeneralSecurityException; 21 | 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | 25 | import com.google.api.client.repackaged.com.google.common.base.Preconditions; 26 | import com.google.api.client.repackaged.com.google.common.base.Strings; 27 | import com.google.api.services.androidpublisher.AndroidPublisher; 28 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits; 29 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Insert; 30 | import com.google.api.services.androidpublisher.model.Apk; 31 | import com.google.api.services.androidpublisher.model.ApksListResponse; 32 | import com.google.api.services.androidpublisher.model.AppEdit; 33 | 34 | /** 35 | * Lists all the apks for a given app. 36 | */ 37 | public class ListApks { 38 | 39 | private static final Log log = LogFactory.getLog(ListApks.class); 40 | 41 | public static void main(String[] args) { 42 | try { 43 | Preconditions.checkArgument(!Strings.isNullOrEmpty(ApplicationConfig.PACKAGE_NAME), 44 | "ApplicationConfig.PACKAGE_NAME cannot be null or empty!"); 45 | 46 | // Create the API service. 47 | final AndroidPublisher service = AndroidPublisherHelper.init( 48 | ApplicationConfig.APPLICATION_NAME, ApplicationConfig.SERVICE_ACCOUNT_EMAIL); 49 | final Edits edits = service.edits(); 50 | 51 | // Create a new edit to make changes. 52 | Insert editRequest = edits 53 | .insert(ApplicationConfig.PACKAGE_NAME, 54 | null /** no content */); 55 | AppEdit appEdit = editRequest.execute(); 56 | 57 | // Get a list of apks. 58 | ApksListResponse apksResponse = edits 59 | .apks() 60 | .list(ApplicationConfig.PACKAGE_NAME, 61 | appEdit.getId()).execute(); 62 | 63 | // Print the apk info. 64 | for (Apk apk : apksResponse.getApks()) { 65 | System.out.println( 66 | String.format("Version: %d - Binary sha1: %s", apk.getVersionCode(), 67 | apk.getBinary().getSha1())); 68 | } 69 | } catch (IOException | GeneralSecurityException ex) { 70 | log.error("Exception was thrown while updating listing", ex); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/UpdateListing.java: -------------------------------------------------------------------------------- 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 java.io.IOException; 20 | import java.security.GeneralSecurityException; 21 | import java.util.Locale; 22 | 23 | import org.apache.commons.logging.Log; 24 | import org.apache.commons.logging.LogFactory; 25 | 26 | import com.google.api.client.repackaged.com.google.common.base.Preconditions; 27 | import com.google.api.client.repackaged.com.google.common.base.Strings; 28 | import com.google.api.services.androidpublisher.AndroidPublisher; 29 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits; 30 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Commit; 31 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Insert; 32 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Listings.Update; 33 | import com.google.api.services.androidpublisher.model.AppEdit; 34 | import com.google.api.services.androidpublisher.model.Listing; 35 | 36 | /** 37 | * Updates US and UK listings. Changes title, short-description, full-description and video for 38 | * en-US and en-GB locales. 39 | */ 40 | public class UpdateListing { 41 | 42 | private static final Log log = LogFactory.getLog(UpdateListing.class); 43 | 44 | private static final String US_LISTING_TITLE = "App Title US"; 45 | private static final String US_LISTING_SHORT_DESCRITPION = "Bacon ipsum"; 46 | private static final String US_LISTING_FULL_DESCRIPTION = "Dessert trunk truck"; 47 | 48 | private static final String UK_LISTING_TITLE = "App Title UK"; 49 | private static final String UK_LISTING_SHORT_DESCRITPION = "Pancetta ipsum"; 50 | private static final String UK_LISTING_FULL_DESCRIPTION = "Pudding boot lorry"; 51 | 52 | private static final String LISTINGS_PROMO_VIDEO = 53 | "https://www.youtube.com/watch?v=ZNSLQlNSPu8"; 54 | 55 | public static void main(String[] args) { 56 | try { 57 | Preconditions.checkArgument(!Strings.isNullOrEmpty(ApplicationConfig.PACKAGE_NAME), 58 | "ApplicationConfig.PACKAGE_NAME cannot be null or empty!"); 59 | 60 | // Create the API service. 61 | AndroidPublisher service = AndroidPublisherHelper.init( 62 | ApplicationConfig.APPLICATION_NAME, ApplicationConfig.SERVICE_ACCOUNT_EMAIL); 63 | final Edits edits = service.edits(); 64 | 65 | // Create an edit to update listing for application. 66 | Insert editRequest = edits 67 | .insert(ApplicationConfig.PACKAGE_NAME, 68 | null /** no content */); 69 | AppEdit edit = editRequest.execute(); 70 | final String editId = edit.getId(); 71 | log.info(String.format("Created edit with id: %s", editId)); 72 | 73 | // Update listing for US version of the application. 74 | final Listing newUsListing = new Listing(); 75 | newUsListing.setTitle(US_LISTING_TITLE) 76 | .setFullDescription(US_LISTING_FULL_DESCRIPTION) 77 | .setShortDescription(US_LISTING_SHORT_DESCRITPION) 78 | .setVideo(LISTINGS_PROMO_VIDEO); 79 | 80 | Update updateUSListingsRequest = edits 81 | .listings() 82 | .update(ApplicationConfig.PACKAGE_NAME, 83 | editId, 84 | Locale.US.toString(), 85 | newUsListing); 86 | Listing updatedUsListing = updateUSListingsRequest.execute(); 87 | log.info(String.format("Created new US app listing with title: %s", 88 | updatedUsListing.getTitle())); 89 | 90 | // Create and update listing for UK version of the application. 91 | final Listing newUkListing = new Listing(); 92 | newUkListing.setTitle(UK_LISTING_TITLE) 93 | .setFullDescription(UK_LISTING_FULL_DESCRIPTION) 94 | .setShortDescription(UK_LISTING_SHORT_DESCRITPION) 95 | .setVideo(LISTINGS_PROMO_VIDEO); 96 | 97 | Update updateUkListingsRequest = edits 98 | .listings() 99 | .update(ApplicationConfig.PACKAGE_NAME, 100 | editId, 101 | Locale.UK.toString(), 102 | newUkListing); 103 | Listing updatedUkListing = updateUkListingsRequest.execute(); 104 | log.info(String.format("Created new UK app listing with title: %s", 105 | updatedUkListing.getTitle())); 106 | 107 | // Commit changes for edit. 108 | Commit commitRequest = edits.commit(ApplicationConfig.PACKAGE_NAME, editId); 109 | AppEdit appEdit = commitRequest.execute(); 110 | log.info(String.format("App edit with id %s has been comitted", appEdit.getId())); 111 | 112 | } catch (IOException | GeneralSecurityException ex) { 113 | log.error("Exception was thrown while updating listing", ex); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /v3/java/src/com/google/play/developerapi/samples/UploadApkWithListing.java: -------------------------------------------------------------------------------- 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.services.androidpublisher.model.LocalizedText; 20 | import com.google.api.services.androidpublisher.model.TrackRelease; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.net.URISyntaxException; 24 | import java.security.GeneralSecurityException; 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.Locale; 29 | 30 | import org.apache.commons.logging.Log; 31 | import org.apache.commons.logging.LogFactory; 32 | 33 | import com.google.api.client.http.AbstractInputStreamContent; 34 | import com.google.api.client.http.FileContent; 35 | import com.google.api.client.repackaged.com.google.common.base.Preconditions; 36 | import com.google.api.client.repackaged.com.google.common.base.Strings; 37 | import com.google.api.services.androidpublisher.AndroidPublisher; 38 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits; 39 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Commit; 40 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Insert; 41 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Apks.Upload; 42 | import com.google.api.services.androidpublisher.AndroidPublisher.Edits.Tracks.Update; 43 | import com.google.api.services.androidpublisher.model.Apk; 44 | import com.google.api.services.androidpublisher.model.AppEdit; 45 | import com.google.api.services.androidpublisher.model.Track; 46 | 47 | /** 48 | * Uploads an apk to the beta track and updates recent changes description. 49 | */ 50 | public class UploadApkWithListing { 51 | 52 | private static final Log log = LogFactory.getLog(UploadApkWithListing.class); 53 | 54 | private static final String RECENT_CHANGES_TEXT = "Release recent changes en-US"; 55 | 56 | /** 57 | * Track for uploading the apk, can be 'alpha', beta', 'production' or 58 | * 'rollout'. 59 | */ 60 | private static final String TRACK_BETA = "beta"; 61 | 62 | public static void main(String[] args) { 63 | try { 64 | Preconditions.checkArgument(!Strings.isNullOrEmpty(ApplicationConfig.PACKAGE_NAME), 65 | "ApplicationConfig.PACKAGE_NAME cannot be null or empty!"); 66 | 67 | // Create the API service. 68 | AndroidPublisher service = AndroidPublisherHelper.init( 69 | ApplicationConfig.APPLICATION_NAME, ApplicationConfig.SERVICE_ACCOUNT_EMAIL); 70 | final Edits edits = service.edits(); 71 | 72 | // Create a new edit to make changes. 73 | Insert editRequest = edits 74 | .insert(ApplicationConfig.PACKAGE_NAME, 75 | null /** no content */); 76 | AppEdit edit = editRequest.execute(); 77 | final String editId = edit.getId(); 78 | log.info(String.format("Created edit with id: %s", editId)); 79 | 80 | // Upload new apk to developer console 81 | final String apkPath = UploadApkWithListing.class 82 | .getResource(ApplicationConfig.APK_FILE_PATH) 83 | .toURI().getPath(); 84 | final AbstractInputStreamContent apkFile = 85 | new FileContent(AndroidPublisherHelper.MIME_TYPE_APK, new File(apkPath)); 86 | Upload uploadRequest = edits 87 | .apks() 88 | .upload(ApplicationConfig.PACKAGE_NAME, 89 | editId, 90 | apkFile); 91 | Apk apk = uploadRequest.execute(); 92 | log.info(String.format("Version code %d has been uploaded", 93 | apk.getVersionCode())); 94 | 95 | // Assign apk to beta track. 96 | List apkVersionCodes = new ArrayList<>(); 97 | apkVersionCodes.add(Long.valueOf(apk.getVersionCode())); 98 | Update updateTrackRequest = edits 99 | .tracks() 100 | .update(ApplicationConfig.PACKAGE_NAME, 101 | editId, 102 | TRACK_BETA, 103 | new Track().setReleases( 104 | Collections.singletonList( 105 | new TrackRelease() 106 | .setName("My Beta Release") 107 | .setVersionCodes(apkVersionCodes) 108 | .setStatus("completed") 109 | .setReleaseNotes(Collections.singletonList( 110 | new LocalizedText() 111 | .setLanguage(Locale.US.toString()) 112 | .setText(RECENT_CHANGES_TEXT)))))); 113 | Track updatedTrack = updateTrackRequest.execute(); 114 | log.info(String.format("Track %s has been updated.", updatedTrack.getTrack())); 115 | 116 | 117 | // Commit changes for edit. 118 | Commit commitRequest = edits.commit(ApplicationConfig.PACKAGE_NAME, editId); 119 | AppEdit appEdit = commitRequest.execute(); 120 | log.info(String.format("App edit with id %s has been comitted", appEdit.getId())); 121 | 122 | } catch (IOException | URISyntaxException | GeneralSecurityException ex) { 123 | log.error( 124 | "Exception was thrown while uploading apk and updating recent changes", 125 | ex); 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /v3/java/src/resources/client_secrets.json: -------------------------------------------------------------------------------- 1 | { 2 | "installed": { 3 | "client_id": "[[INSERT CLIENT ID HERE]]", 4 | "client_secret": "[[INSERT CLIENT SECRET HERE]]", 5 | "redirect_uris": [], 6 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 7 | "token_uri": "https://accounts.google.com/o/oauth2/token" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /v3/python/README.md: -------------------------------------------------------------------------------- 1 | # Google Play Developer Publishing API samples 2 | 3 | A collection of command-line samples for the Play Developer Publishing API. 4 | 5 | ## Installation 6 | 7 | 1. Download Google APIs Client Library for Python (google-api-python-client): 8 | https://code.google.com/p/google-api-python-client/ 9 | 10 | or use pip: 11 | 12 | ```bash 13 | $ pip install google-api-python-client 14 | ``` 15 | 16 | 2. Make sure you can import the client library: 17 | 18 | ```bash 19 | $ python 20 | >>> import apiclient 21 | >>> 22 | ``` 23 | 24 | ## First request using OAuth2: Installed application 25 | 26 | 1. Edit the `client_secrets.json` file and add the client ID and client secret. 27 | 28 | 2. Execute any of the scripts to begin the auth flow: 29 | 30 | ```bash 31 | $ python basic_list_apks.py com.myapp.package 32 | ``` 33 | 34 | A browser window will open and ask you to login. Make sure the account has 35 | enough permissions in the Google Play Developer console. 36 | 37 | 3. Accept the permissions dialog. The browser should display 38 | 39 | `The authentication flow has completed.` 40 | 41 | Close the window and go back to the shell. 42 | 43 | 4. The script will output a list of apks. 44 | 45 | 5. The tokens will be stored in `androidpublisher.dat`. Remove this file to restart the 46 | auth flow. 47 | 48 | 49 | ## First request using OAuth2: Service accounts 50 | 51 | 1. Edit `basic_list_apks_service_account.py` and add the service account Email 52 | address. 53 | 54 | 2. Copy the service account key file, generated in the Google APIs Console into 55 | the same directory and rename it to `key.p12`. 56 | 57 | 3. Execute the script: 58 | 59 | ```bash 60 | $ python basic_list_apks_service_account.py com.myapp.package 61 | ``` 62 | 63 | 4. The script will output a list of apks. 64 | 65 | -------------------------------------------------------------------------------- /v3/python/basic_list_apks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Lists all the apks for a given app.""" 18 | 19 | import argparse 20 | import sys 21 | from apiclient import sample_tools 22 | from oauth2client import client 23 | 24 | # Declare command-line flags. 25 | argparser = argparse.ArgumentParser(add_help=False) 26 | argparser.add_argument('package_name', 27 | help='The package name. Example: com.android.sample') 28 | 29 | 30 | def main(argv): 31 | # Authenticate and construct service. 32 | service, flags = sample_tools.init( 33 | argv, 34 | 'androidpublisher', 35 | 'v3', 36 | __doc__, 37 | __file__, 38 | parents=[argparser], 39 | scope='https://www.googleapis.com/auth/androidpublisher') 40 | 41 | # Process flags and read their values. 42 | package_name = flags.package_name 43 | 44 | try: 45 | 46 | edit_request = service.edits().insert(body={}, packageName=package_name) 47 | result = edit_request.execute() 48 | edit_id = result['id'] 49 | 50 | apks_result = service.edits().apks().list( 51 | editId=edit_id, packageName=package_name).execute() 52 | 53 | for apk in apks_result['apks']: 54 | print 'versionCode: %s, binary.sha1: %s' % ( 55 | apk['versionCode'], apk['binary']['sha1']) 56 | 57 | except client.AccessTokenRefreshError: 58 | print ('The credentials have been revoked or expired, please re-run the ' 59 | 'application to re-authorize') 60 | 61 | if __name__ == '__main__': 62 | main(sys.argv) 63 | -------------------------------------------------------------------------------- /v3/python/basic_list_apks_service_account.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Lists all the apks for a given app.""" 18 | 19 | import argparse 20 | 21 | from apiclient.discovery import build 22 | import httplib2 23 | from oauth2client import client 24 | 25 | 26 | SERVICE_ACCOUNT_EMAIL = ( 27 | 'ENTER_YOUR_SERVICE_ACCOUNT_EMAIL_HERE@developer.gserviceaccount.com') 28 | 29 | # Declare command-line flags. 30 | argparser = argparse.ArgumentParser(add_help=False) 31 | argparser.add_argument('package_name', 32 | help='The package name. Example: com.android.sample') 33 | 34 | 35 | def main(): 36 | # Load the key in PKCS 12 format that you downloaded from the Google APIs 37 | # Console when you created your Service account. 38 | f = file('key.p12', 'rb') 39 | key = f.read() 40 | f.close() 41 | 42 | # Create an httplib2.Http object to handle our HTTP requests and authorize it 43 | # with the Credentials. Note that the first parameter, service_account_name, 44 | # is the Email address created for the Service account. It must be the email 45 | # address associated with the key that was created. 46 | credentials = client.SignedJwtAssertionCredentials( 47 | SERVICE_ACCOUNT_EMAIL, 48 | key, 49 | scope='https://www.googleapis.com/auth/androidpublisher') 50 | http = httplib2.Http() 51 | http = credentials.authorize(http) 52 | 53 | service = build('androidpublisher', 'v3', http=http) 54 | 55 | # Process flags and read their values. 56 | flags = argparser.parse_args() 57 | 58 | package_name = flags.package_name 59 | 60 | try: 61 | 62 | edit_request = service.edits().insert(body={}, packageName=package_name) 63 | result = edit_request.execute() 64 | edit_id = result['id'] 65 | 66 | apks_result = service.edits().apks().list( 67 | editId=edit_id, packageName=package_name).execute() 68 | 69 | for apk in apks_result['apks']: 70 | print('versionCode: %s, binary.sha1: %s' % ( 71 | apk['versionCode'], apk['binary']['sha1'])) 72 | 73 | except client.AccessTokenRefreshError: 74 | print ('The credentials have been revoked or expired, please re-run the ' 75 | 'application to re-authorize') 76 | 77 | if __name__ == '__main__': 78 | main() 79 | -------------------------------------------------------------------------------- /v3/python/basic_upload_apks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the 'License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Uploads an apk to the alpha track.""" 18 | 19 | import argparse 20 | import sys 21 | from apiclient import sample_tools 22 | from oauth2client import client 23 | 24 | TRACK = 'alpha' # Can be 'alpha', beta', 'production' or 'rollout' 25 | 26 | # Declare command-line flags. 27 | argparser = argparse.ArgumentParser(add_help=False) 28 | argparser.add_argument('package_name', 29 | help='The package name. Example: com.android.sample') 30 | argparser.add_argument('apk_file', 31 | nargs='?', 32 | default='test.apk', 33 | help='The path to the APK file to upload.') 34 | 35 | 36 | def main(argv): 37 | # Authenticate and construct service. 38 | service, flags = sample_tools.init( 39 | argv, 40 | 'androidpublisher', 41 | 'v3', 42 | __doc__, 43 | __file__, parents=[argparser], 44 | scope='https://www.googleapis.com/auth/androidpublisher') 45 | 46 | # Process flags and read their values. 47 | package_name = flags.package_name 48 | apk_file = flags.apk_file 49 | 50 | try: 51 | edit_request = service.edits().insert(body={}, packageName=package_name) 52 | result = edit_request.execute() 53 | edit_id = result['id'] 54 | 55 | apk_response = service.edits().apks().upload( 56 | editId=edit_id, 57 | packageName=package_name, 58 | media_body=apk_file).execute() 59 | 60 | print 'Version code %d has been uploaded' % apk_response['versionCode'] 61 | 62 | track_response = service.edits().tracks().update( 63 | editId=edit_id, 64 | track=TRACK, 65 | packageName=package_name, 66 | body={u'releases': [{ 67 | u'name': u'My first API release', 68 | u'versionCodes': [str(apk_response['versionCode'])], 69 | u'status': u'completed', 70 | }]}).execute() 71 | 72 | print 'Track %s is set with releases: %s' % ( 73 | track_response['track'], str(track_response['releases'])) 74 | 75 | commit_request = service.edits().commit( 76 | editId=edit_id, packageName=package_name).execute() 77 | 78 | print 'Edit "%s" has been committed' % (commit_request['id']) 79 | 80 | except client.AccessTokenRefreshError: 81 | print ('The credentials have been revoked or expired, please re-run the ' 82 | 'application to re-authorize') 83 | 84 | if __name__ == '__main__': 85 | main(sys.argv) 86 | -------------------------------------------------------------------------------- /v3/python/client_secrets.json: -------------------------------------------------------------------------------- 1 | { 2 | "installed": { 3 | "client_id": "[[INSERT CLIENT ID HERE]]", 4 | "client_secret": "[[INSERT CLIENT SECRET HERE]]", 5 | "redirect_uris": [], 6 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 7 | "token_uri": "https://accounts.google.com/o/oauth2/token" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /v3/python/update_listings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the 'License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Changes the description, promo text and title of an app in en-US and en-GB. 18 | """ 19 | 20 | import argparse 21 | import sys 22 | from apiclient import sample_tools 23 | from oauth2client import client 24 | 25 | TRACK = 'alpha' # Can be 'alpha', beta', 'production' or 'rollout' 26 | 27 | # Declare command-line flags. 28 | argparser = argparse.ArgumentParser(add_help=False) 29 | argparser.add_argument('package_name', 30 | help='The package name. Example: com.android.sample') 31 | 32 | 33 | def main(argv): 34 | # Authenticate and construct service. 35 | service, flags = sample_tools.init( 36 | argv, 37 | 'androidpublisher', 38 | 'v2', 39 | __doc__, 40 | __file__, parents=[argparser], 41 | scope='https://www.googleapis.com/auth/androidpublisher') 42 | 43 | # Process flags and read their values. 44 | package_name = flags.package_name 45 | 46 | try: 47 | edit_request = service.edits().insert(body={}, packageName=package_name) 48 | result = edit_request.execute() 49 | edit_id = result['id'] 50 | 51 | listing_response_us = service.edits().listings().update( 52 | editId=edit_id, packageName=package_name, language='en-US', 53 | body={'fullDescription': 'Dessert trunk truck', 54 | 'shortDescription': 'Bacon ipsum', 55 | 'title': 'App Title US'}).execute() 56 | 57 | print ('Listing for language %s was updated.' 58 | % listing_response_us['language']) 59 | 60 | listing_response_gb = service.edits().listings().update( 61 | editId=edit_id, packageName=package_name, language='en-GB', 62 | body={'fullDescription': 'Pudding boot lorry', 63 | 'shortDescription': 'Pancetta ipsum', 64 | 'title': 'App Title UK'}).execute() 65 | 66 | print ('Listing for language %s was updated.' 67 | % listing_response_gb['language']) 68 | 69 | commit_request = service.edits().commit( 70 | editId=edit_id, packageName=package_name).execute() 71 | 72 | print 'Edit "%s" has been committed' % (commit_request['id']) 73 | 74 | except client.AccessTokenRefreshError: 75 | print ('The credentials have been revoked or expired, please re-run the ' 76 | 'application to re-authorize') 77 | 78 | if __name__ == '__main__': 79 | main(sys.argv) 80 | -------------------------------------------------------------------------------- /v3/python/upload_apks_rollout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the 'License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Uploads apk to rollout track with user fraction.""" 18 | 19 | import argparse 20 | import sys 21 | from apiclient import sample_tools 22 | from oauth2client import client 23 | 24 | TRACK = 'rollout' 25 | USER_FRACTION = 0.2 26 | 27 | # Declare command-line flags. 28 | argparser = argparse.ArgumentParser(add_help=False) 29 | argparser.add_argument('package_name', 30 | help='The package name. Example: com.android.sample') 31 | argparser.add_argument('apk_file', 32 | nargs='?', 33 | default='test.apk', 34 | help='The path to the APK file to upload.') 35 | 36 | 37 | def main(argv): 38 | # Authenticate and construct service. 39 | service, flags = sample_tools.init( 40 | argv, 41 | 'androidpublisher', 42 | 'v3', 43 | __doc__, 44 | __file__, parents=[argparser], 45 | scope='https://www.googleapis.com/auth/androidpublisher') 46 | 47 | # Process flags and read their values. 48 | package_name = flags.package_name 49 | apk_file = flags.apk_file 50 | 51 | try: 52 | edit_request = service.edits().insert(body={}, packageName=package_name) 53 | result = edit_request.execute() 54 | edit_id = result['id'] 55 | 56 | apk_response = service.edits().apks().upload( 57 | editId=edit_id, packageName=package_name, media_body=apk_file).execute() 58 | 59 | print 'Version code %d has been uploaded' % apk_response['versionCode'] 60 | 61 | track_response = service.edits().tracks().update( 62 | editId=edit_id, 63 | track=TRACK, 64 | packageName=package_name, 65 | body={u'releases': [{ 66 | u'name': u'My first API release', 67 | u'versionCodes': [str([apk_response['versionCode']])], 68 | u'userFraction': USER_FRACTION, 69 | u'status': u'inProgress', 70 | }]}).execute() 71 | 72 | print 'Track %s is set with releases: %s' % ( 73 | track_response['track'], str(track_response['releases'])) 74 | 75 | commit_request = service.edits().commit( 76 | editId=edit_id, packageName=package_name).execute() 77 | 78 | print 'Edit "%s" has been committed' % (commit_request['id']) 79 | 80 | except client.AccessTokenRefreshError: 81 | print ('The credentials have been revoked or expired, please re-run the ' 82 | 'application to re-authorize') 83 | 84 | if __name__ == '__main__': 85 | main(sys.argv) 86 | -------------------------------------------------------------------------------- /v3/python/upload_apks_with_listing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2014 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the 'License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Uploads apk to alpha track and updates its listing properties.""" 18 | 19 | import argparse 20 | import sys 21 | from apiclient import sample_tools 22 | from oauth2client import client 23 | 24 | TRACK = 'alpha' # Can be 'alpha', beta', 'production' or 'rollout' 25 | 26 | # Declare command-line flags. 27 | argparser = argparse.ArgumentParser(add_help=False) 28 | argparser.add_argument('package_name', 29 | help='The package name. Example: com.android.sample') 30 | argparser.add_argument('apk_file', 31 | nargs='?', 32 | default='test.apk', 33 | help='The path to the APK file to upload.') 34 | 35 | 36 | def main(argv): 37 | # Authenticate and construct service. 38 | service, flags = sample_tools.init( 39 | argv, 40 | 'androidpublisher', 41 | 'v3', 42 | __doc__, 43 | __file__, parents=[argparser], 44 | scope='https://www.googleapis.com/auth/androidpublisher') 45 | 46 | # Process flags and read their values. 47 | package_name = flags.package_name 48 | apk_file = flags.apk_file 49 | 50 | try: 51 | edit_request = service.edits().insert(body={}, packageName=package_name) 52 | result = edit_request.execute() 53 | edit_id = result['id'] 54 | 55 | apk_response = service.edits().apks().upload( 56 | editId=edit_id, 57 | packageName=package_name, 58 | media_body=apk_file).execute() 59 | 60 | print 'Version code %d has been uploaded' % apk_response['versionCode'] 61 | 62 | track_response = service.edits().tracks().update( 63 | editId=edit_id, 64 | track=TRACK, 65 | packageName=package_name, 66 | body={u'releases': [{ 67 | u'name': u'My first API release with release notes', 68 | u'versionCodes': [str([apk_response['versionCode']])], 69 | u'releaseNotes': [ 70 | {u'recentChanges': u'Apk recent changes in en-US'}, 71 | ], 72 | u'status': u'completed', 73 | }]}).execute() 74 | 75 | print 'Track %s is set with releases: %s' % ( 76 | track_response['track'], str(track_response['releases'])) 77 | 78 | commit_request = service.edits().commit( 79 | editId=edit_id, packageName=package_name).execute() 80 | 81 | print 'Edit "%s" has been committed' % (commit_request['id']) 82 | 83 | except client.AccessTokenRefreshError: 84 | print ('The credentials have been revoked or expired, please re-run the ' 85 | 'application to re-authorize') 86 | 87 | if __name__ == '__main__': 88 | main(sys.argv) 89 | --------------------------------------------------------------------------------