Last active
January 19, 2022 10:27
-
-
Save BransonGitomeh/4f9f04c23e0f413e9c2f38d38697ed20 to your computer and use it in GitHub Desktop.
Script to upload apk to playstore, can be added to CI step to automate publications
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env NODE_NO_WARNINGS=1 node | |
const { google } = require('googleapis'); | |
const Promise = require('bluebird'); | |
const fs = require('fs'); | |
const settings = require('./config/settings.json'); | |
const { version } = require('./package.json'); | |
// Enable API access into the Developer Console: https://play.google.com/apps/publish/?account=7639196906174529268#ApiAccessPlace | |
// Create a service account | |
// Download the JSON and save it here | |
// Make sure the email of the JSON is added to the apps for release manager role: | |
// https://play.google.com/apps/publish/?account=7639196906174529268#AdminPlace | |
const key = require('./secrets.json'); | |
// editing "scope" allowed for OAuth2 | |
const scopes = ['https://www.googleapis.com/auth/androidpublisher']; | |
process.exitCode = 1; | |
const { OAuth2 } = google.auth; | |
const oauth2Client = new OAuth2(); | |
const jwtClient = new google.auth.JWT( | |
key.client_email, | |
null, | |
key.private_key, | |
scopes, | |
null, | |
); | |
const play = google.androidpublisher({ | |
version: 'v3', | |
auth: oauth2Client, | |
params: { | |
// default options | |
// this is the package name for your initial app you've already set up on the Play Store | |
packageName: settings.app.id, | |
}, | |
}); | |
google.options({ auth: oauth2Client }); | |
/** | |
* Sets our authorization token and begins an edit transaction. | |
*/ | |
function startEdit() { | |
return new Promise(((resolve, reject) => { | |
jwtClient.authorize((err, tokens) => { | |
if (err) { | |
console.log('authorize error', err); | |
process.exit(1); | |
return; | |
} | |
// Set the credentials before we doing anything. | |
oauth2Client.setCredentials(tokens); | |
play.edits.insert( | |
{ | |
packageName: settings.app.id, | |
}, | |
(insertError, edit) => { | |
if (insertError || !edit) { | |
console.log('Insert errors', insertError); | |
reject(err); | |
} | |
resolve({ | |
edit: edit.data, | |
}); | |
}, | |
); | |
}); | |
})); | |
} | |
const start = async () => { | |
const { packageName = 'io.braiven.databank' } = process.env; | |
console.log(`Upload started for ${packageName} for version ${version}`); | |
const { | |
edit: { id: editId }, | |
} = await startEdit(); | |
const builds = ['app-armeabi-v7a-release.apk', 'app-x86-release.apk']; | |
const availableOutputFiles = fs.readdirSync('./android/app/build/outputs/apk/release'); | |
console.log('Available builds are', availableOutputFiles.join(', ')); | |
const uploadRes = await Promise.all( | |
builds.map(async (build) => { | |
try { | |
// dont try read a build thats not on the FS | |
if (!availableOutputFiles.includes(build)) { return; } | |
const apk = fs.readFileSync(`./android/app/build/outputs/apk/release/${build}`); | |
console.log(`Attempting Upload for cpu build ${build}`); | |
const { | |
data: { | |
versionCode: uploadedVersionCode, | |
binary: { sha256 }, | |
}, | |
} = await play.edits.apks.upload({ | |
editId, | |
packageName, | |
media: { | |
mimeType: 'application/vnd.android.package-archive', | |
body: apk, | |
}, | |
}); | |
console.log(`Successfully uploaded version:${uploadedVersionCode}, build:${build}, sha256:${sha256}`); | |
return { versionCode: uploadedVersionCode, sha256 }; | |
} catch (err) { | |
console.log(`Upload for ${build} failed`, err.message); | |
throw err; | |
} | |
}), | |
); | |
console.log(JSON.stringify({ uploadRes }, null, '\t')); | |
// Assign apk to beta track. | |
const { data: trackRes } = await play.edits.tracks.update({ | |
editId, | |
track: 'beta', | |
packageName, | |
releases: [ | |
{ | |
versionCodes: [uploadRes[0].versionCode], | |
status: 'completed', | |
}, | |
], | |
}); | |
console.log('Placing edit on beta track', trackRes); | |
const { data: lists } = await play.edits.apks.list({ editId }); | |
console.log('Edits apk list', lists.apks.map(apk => apk.versionCode)); | |
// const { data: lists } = await play.edits.apks.u; | |
const { data: commit } = await play.edits.commit({ | |
editId, | |
packageName, | |
}); | |
console.log({ commit }); | |
}; | |
start().catch((err) => { | |
const errString = 'Upload failed with the following errors'; | |
if (err.errors) { | |
console.error(`${errString} ${JSON.stringify(err.errors, null, '\t')}`); | |
} else { | |
console.error(`${errString} ${err}`); | |
} | |
process.exit(1); | |
}); |
After you do this, users on each track will be given the updated version of the APK. (As with all edits, it can take several hours for the changes to take effect.)
has served my team for quite some time now, added some improvements to exit the process with clear logs incase of failures
Is this up to date? I'm getting invalid request errors. Also how is this different / better than the apkup
package?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
important notes
yarn publish-release