Autoincrement VersionCode with optional gradle properties

I am creating an android application with gradle. So far I have used the manifest file to increase the version of Code, but I would like to read the version of Code from an external file, and depending on whether it is a release flavor or a debugging flavor, increase the version of Code. I tried additional properties, but you cannot save them, which means that the next time I build it, I get the same version code. Any help would be greatly appreciated!

project.ext{ devVersionCode = 13 releaseVersionCode = 1 } buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' repositories { mavenCentral() } dependencies { compile project(':Cropper') compile "com.android.support:appcompat-v7:18.0.+" compile "com.android.support:support-v4:18.0.+" compile fileTree(dir: 'libs', include: '*.jar') } def getReleaseVersionCode() { def version = project.releaseVersionCode + 1 project.releaseVersionCode = version println sprintf("Returning version %d", version) return version } def getDevVersionCode() { def version = project.devVersionCode + 1 project.devVersionCode = version println sprintf("Returning version %d", version) return version } def getLastVersioName(versionCode) { return "0.0." + versionCode } android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { minSdkVersion 9 targetSdkVersion 19 } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } } buildTypes { release { runProguard true proguardFile getDefaultProguardFile('proguard-android-optimize.txt') proguardFile 'proguard.cfg' debuggable false signingConfig null zipAlign false } debug { versionNameSuffix "-DEBUG" } } productFlavors { dev { packageName = 'com.swisscom.docsafe.debug' versionCode getDevVersionCode() versionName getLastVersioName(project.devVersionCode) } prod { packageName = 'com.swisscom.docsafe' versionCode getReleaseVersionCode() versionName getLastVersioName(project.releaseVersionCode) } } } task wrapper(type: Wrapper) { gradleVersion = '1.8' } 
+111
android android-gradle build.gradle gradle
Jan 28 '14 at 12:16
source share
15 answers

I would like to read versionCode from an external file

I am sure that there are many possible solutions; here is one:

 android { compileSdkVersion 18 buildToolsVersion "18.1.0" def versionPropsFile = file('version.properties') if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) def code = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) defaultConfig { versionCode code versionName "1.1" minSdkVersion 14 targetSdkVersion 18 } } else { throw new GradleException("Could not read version.properties!") } // rest of android block goes here } 

This code expects an existing version.properties file, which you will create manually before the first build with VERSION_CODE=8 .

This code simply changes the version code in each assembly - you will need to expand the technique to process the version code for each version.

You can see an example Versioning project that demonstrates this code.

+190
Jan 28 '14 at 12:37
source share

Here is a modernization of my previous answer, which can be seen below. This one works with Gradle 4.4 and Android Studio 3.1.1 .

What this script does:

  • Creates a version.properties file if it doesn’t exist (Paul Cantrell’s voice below, this is where I got the idea from, if you like this answer)
  • For each build, debug version, or any click of the start button in Android Studio, the number of VERSION_BUILD increases.
  • Each time you build a release, your Android versionCode for the game store increases and the number of your patch increases.
  • Bonus: after the build is complete, copy your apk to projectDir/apk to make it more accessible.

This script will create a version number that looks like v1.3.4 (123) and create an apk file such as AppName-v1.3.4.apk .

 Major version βŒ„ βŒ„ Build version v1.3.4 (123) Minor version βŒƒ|βŒƒ Patch version 

Basic version: must be manually modified for large changes.

Minor version: must be manually modified for slightly less significant changes.

Patch version: increases when running gradle assembleRelease

Build Version: Increases Each Build

Version number: The same as the version of the patch, this is for the version code, which the Play Store should increase for each new apk download.

Just change the content in the comments marked 1 - 3 below, and the script should do the rest. :)

 android { compileSdkVersion 27 buildToolsVersion '27.0.3' def versionPropsFile = file('version.properties') def value = 0 Properties versionProps = new Properties() if (!versionPropsFile.exists()) { versionProps['VERSION_PATCH'] = "0" versionProps['VERSION_NUMBER'] = "0" versionProps['VERSION_BUILD'] = "-1" // I set it to minus one so the first build is 0 which isn't super important. versionProps.store(versionPropsFile.newWriter(), null) } def runTasks = gradle.startParameter.taskNames if ('assembleRelease' in runTasks) { value = 1 } def mVersionName = "" def mFileName = "" if (versionPropsFile.canRead()) { versionProps.load(new FileInputStream(versionPropsFile)) versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString() versionProps['VERSION_NUMBER'] = (versionProps['VERSION_NUMBER'].toInteger() + value).toString() versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString() versionProps.store(versionPropsFile.newWriter(), null) // 1: change major and minor version here mVersionName = "v1.0.${versionProps['VERSION_PATCH']}" // 2: change AppName for your app name mFileName = "AppName-${mVersionName}.apk" defaultConfig { minSdkVersion 21 targetSdkVersion 27 applicationId "com.example.appname" // 3: change to your package name versionCode versionProps['VERSION_NUMBER'].toInteger() versionName "${mVersionName} Build: ${versionProps['VERSION_BUILD']}" } } else { throw new FileNotFoundException("Could not read version.properties!") } if ('assembleRelease' in runTasks) { applicationVariants.all { variant -> variant.outputs.all { output -> if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) { outputFileName = mFileName } } } } task copyApkFiles(type: Copy){ from 'build/outputs/apk/release' into '../apk' include mFileName } afterEvaluate { assembleRelease.doLast { tasks.copyApkFiles.execute() } } signingConfigs { ... } buildTypes { ... } } 

=================================================== ==

INITIAL RESPONSE:

I want versionName to increment automatically as well. So this is just a complement to CommonsWare's answer, which worked perfectly for me. This is what works for me

 defaultConfig { versionCode code versionName "1.1." + code minSdkVersion 14 targetSdkVersion 18 } 

EDIT:

Since I'm a little lazy, I want my versions to work as automatically as possible. I want to have a version of the assembly that increases with each assembly, while the version number and version name only increase when I build the release.

This is what I used over the past year, the basics are taken from CommonsWare's answer and my previous answer, as well as some others. This leads to the following version:

Version name: 1.0.5 (123) β†’ Major.Minor.Patch (Build), Major and Minor are manually changed.

In build.gradle:

 ... android { compileSdkVersion 23 buildToolsVersion '23.0.1' def versionPropsFile = file('version.properties') if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) def value = 0 def runTasks = gradle.startParameter.taskNames if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) { value = 1; } def versionMajor = 1 def versionMinor = 0 def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1 def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value versionProps['VERSION_PATCH'] = versionPatch.toString() versionProps['VERSION_BUILD'] = versionBuild.toString() versionProps['VERSION_NUMBER'] = versionNumber.toString() versionProps.store(versionPropsFile.newWriter(), null) defaultConfig { versionCode versionNumber versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild}) Release" minSdkVersion 14 targetSdkVersion 23 } applicationVariants.all { variant -> variant.outputs.each { output -> def fileNaming = "apk/RELEASES" variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { output.outputFile = new File(getProject().getRootDir(), "${fileNaming}-${versionMajor}.${versionMinor}.${versionPatch}-${outputFile.name}") } } } } } else { throw new GradleException("Could not read version.properties!") } ... } ... 

Patch and versionCode increase if you build your project through the terminal using " assembly", "assemblyRelease " or "aR", which creates a new folder in the root of your project called apk / RELEASE, so you do not need to view build / output / more / more / more to find your apk.

The properties of your version should look like this:

 VERSION_NUMBER=1 VERSION_BUILD=645 VERSION_PATCH=1 

Obviously start with 0. :)

+74
Apr 24 '14 at 10:01
source share

A slightly tightened version of CommonsWare's excellent answer creates a version file if it does not exist:

 def Properties versionProps = new Properties() def versionPropsFile = file('version.properties') if(versionPropsFile.exists()) versionProps.load(new FileInputStream(versionPropsFile)) def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1 versionProps['VERSION_CODE'] = code.toString() versionProps.store(versionPropsFile.newWriter(), null) defaultConfig { versionCode code versionName "1.1" minSdkVersion 14 targetSdkVersion 18 } 
+36
Aug 6 '14 at 17:09 on
source share

I looked at a few options for this and ultimately decided that just using the current time for the Code version instead of trying to automatically increment the version code and check it in my version control system.

Add the following to your build.gradle :

 /** * Use the number of seconds/10 since Jan 1 2016 as the versionCode. * This lets us upload a new build at most every 10 seconds for the * next 680 years. */ def vcode = (int)(((new Date().getTime()/1000) - 1451606400) / 10) android { defaultConfig { ... versionCode vcode } } 

However, if you plan to download assemblies for the year 2696, you can use a different solution.

+26
Jul 28 '16 at 18:11
source share

Another way to get versionCode automatically is to set versionCode to the number of commits in the posted git branch. It performs the following tasks:

  • versionCode generated automatically and sequentially on any computer (including the Continuous Integration server and / or Continuous Deployment ).
  • An application with this versionCode sent to GooglePlay.
  • Does not rely on files outside the repo.
  • Doesn't push anything on the repo
  • Can be manually overridden if necessary.

Using gradle-git library to achieve the above goals. Add the code below to your build.gradle file in the /app directory:

 import org.ajoberstar.grgit.Grgit repositories { mavenCentral() } buildscript { repositories { mavenCentral() } dependencies { classpath 'org.ajoberstar:grgit:1.5.0' } } android { /* if you need a build with a custom version, just add it here, but don't commit to repo, unless you'd like to disable versionCode to be the number of commits in the current branch. ex. project.ext.set("versionCodeManualOverride", 123) */ project.ext.set("versionCodeManualOverride", null) defaultConfig { versionCode getCustomVersionCode() } } def getCustomVersionCode() { if (project.versionCodeManualOverride != null) { return project.versionCodeManualOverride } // current dir is <your proj>/app, so it likely that all your git repo files are in the dir // above. ext.repo = Grgit.open(project.file('..')) // should result in the same value as running // git rev-list <checked out branch name> | wc -l def numOfCommits = ext.repo.log().size() return numOfCommits } 

NOTE. For this method to work, it is best to use it only on the Google Play Store from the same branch (for example, master ).

+16
02 Feb '16 at 19:37
source share

I recently worked on a gradle plugin for Android that automatically generates versionCode and versionName . There are many settings. here you can find more information about this https://github.com/moallemi/gradle-advanced-build-version

+12
Jan 12 '15 at 5:21
source share

Another option, to increase versionCode and versionName , uses a timestamp.

 defaultConfig { versionName "${getVersionNameTimestamp()}" versionCode getVersionCodeTimestamp() } def getVersionNameTimestamp() { return new Date().format('yy.MM.ddHHmm') } def getVersionCodeTimestamp() { def date = new Date() def formattedDate = date.format('yyMMddHHmm') def code = formattedDate.toInteger() println sprintf("VersionCode: %d", code) return code } 

Starting January 1, 2022, formattedDate = date.format ('yyMMddHHmm') exceeds the capacity of integers

+10
Jan 20 '15 at 10:55
source share

To increase the version code only in the release version, follow these steps:

 android { compileSdkVersion 21 buildToolsVersion "21.1.2" def versionPropsFile = file('version.properties') def code = 1; if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) List<String> runTasks = gradle.startParameter.getTaskNames(); def value = 0 for (String item : runTasks) if ( item.contains("assembleRelease")) { value = 1; } code = Integer.parseInt(versionProps['VERSION_CODE']).intValue() + value versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) } else { throw new GradleException("Could not read version.properties!") } defaultConfig { applicationId "com.pack" minSdkVersion 14 targetSdkVersion 21 versionName "1.0."+ code versionCode code } 

expects an existing c://YourProject/app/version.properties , which you will create manually before the first assembly has VERSION_CODE=8

File version.properties :

VERSION_CODE=8

+10
Feb 18 '15 at 14:32
source share

Create version.properties file

 MAJOR=1 MINOR=3 PATCH=6 VERSION_CODE=1 

Change build.gradle :

 android { def _versionCode=0 def _major=0 def _minor=0 def _patch=0 def _applicationId = "com.example.test" def versionPropsFile = file('version.properties') if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) _patch = versionProps['PATCH'].toInteger() + 1 _major = versionProps['MAJOR'].toInteger() _minor = versionProps['MINOR'].toInteger() _versionCode= versionProps['VERSION_CODE'].toInteger()+1 if(_patch==99) { _patch=0 _minor=_minor+1 } if(_major==99){ _major=0 _major=_major+1 } versionProps['MAJOR']=_major.toString() versionProps['MINOR']=_minor.toString() versionProps['PATCH']=_patch.toString() versionProps['VERSION_CODE']=_versionCode.toString() versionProps.store(versionPropsFile.newWriter(), null) } else { throw new GradleException("Could not read version.properties!") } def _versionName = "${_major}.${_versionCode}.${_minor}.${_patch}" compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId _applicationId minSdkVersion 11 targetSdkVersion 23 versionCode _versionCode versionName _versionName } 

}

Output: 1.1.3.6

+3
Jun 10 '16 at 4:52
source share

Define versionName in AndroidManifest.xml

 android:versionName="5.1.5" 

Inside android{...} block in the build.gradle level build.gradle :

 defaultConfig { applicationId "com.example.autoincrement" minSdkVersion 18 targetSdkVersion 23 multiDexEnabled true def version = getIncrementationVersionName() versionName version } 

External android{...} block in build.gradle level build.gradle :

 def getIncrementedVersionName() { List<String> runTasks = gradle.startParameter.getTaskNames(); //find version name in manifest def manifestFile = file('src/main/AndroidManifest.xml') def matcher = Pattern.compile('versionName=\"(\\d+)\\.(\\d+)\\.(\\d+)\"').matcher(manifestFile.getText()) matcher.find() //extract versionName parts def firstPart = Integer.parseInt(matcher.group(1)) def secondPart = Integer.parseInt(matcher.group(2)) def thirdPart = Integer.parseInt(matcher.group(3)) //check is runTask release or not // if release - increment version for (String item : runTasks) { if (item.contains("assemble") && item.contains("Release")) { thirdPart++ if (thirdPart == 10) { thirdPart = 0; secondPart++ if (secondPart == 10) { secondPart = 0; firstPart++ } } } } def versionName = firstPart + "." + secondPart + "." + thirdPart // update manifest def manifestContent = matcher.replaceAll('versionName=\"' + versionName + '\"') manifestFile.write(manifestContent) println "incrementVersionName = " + versionName return versionName } 

After creating the bonded APK:

 android:versionName="5.1.6" 

Note. If your versionName is different from mine, you need to change the regular expression and extract the partial logic .

+2
May 20 '16 at 14:09
source share

Using the Gradle Task Schedule , we can check / change the type of assembly .

The basic idea is to increase the versionCode in each assembly. On each build counter, stored in the version.properties file. It will be updated with each new build of the APK and will replace the versionCode line in the build.gradle file with this counter increment value.

 apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion '25.0.2' def versionPropsFile = file('version.properties') def versionBuild /*Setting default value for versionBuild which is the last incremented value stored in the file */ if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) versionBuild = versionProps['VERSION_BUILD'].toInteger() } else { throw new FileNotFoundException("Could not read version.properties!") } /*Wrapping inside a method avoids auto incrementing on every gradle task run. Now it runs only when we build apk*/ ext.autoIncrementBuildNumber = { if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1 versionProps['VERSION_BUILD'] = versionBuild.toString() versionProps.store(versionPropsFile.nminSdkVersion 14 targetSdkVersion 21 versionCode 1ewWriter(), null) } else { throw new FileNotFoundException("Could not read version.properties!") } } defaultConfig { minSdkVersion 16 targetSdkVersion 21 versionCode 1 versionName "1.0.0." + versionBuild } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // Hook to check if the release/debug task is among the tasks to be executed. //Let make use of it gradle.taskGraph.whenReady {taskGraph -> if (taskGraph.hasTask(assembleDebug)) { /* when run debug task */ autoIncrementBuildNumber() } else if (taskGraph.hasTask(assembleRelease)) { /* when run release task */ autoIncrementBuildNumber() } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.3.1' } 

Put the above script inside your build.gradle file of the main module.

Help site: http://devdeeds.com/auto-increment-build-number-using-gradle-in-android/

Thank you and respectfully!

0
May 15 '16 at 2:40
source share

Credits for CommonsWare (accepted answer) Paul Cantrell (create a file if it does not exist) ahmad aghazadeh (name and version code)

So, I combined all my ideas and came up with this. This is a drag and drop solution to see exactly what the first post set.

It will automatically update versionCode and versionName according to release status. Of course, you can move variables to suit your needs.

 def _versionCode=0 def versionPropsFile = file('version.properties') def Properties versionProps = new Properties() if(versionPropsFile.exists()) versionProps.load(new FileInputStream(versionPropsFile)) def _patch = (versionProps['PATCH'] ?: "0").toInteger() + 1 def _major = (versionProps['MAJOR'] ?: "0").toInteger() def _minor = (versionProps['MINOR'] ?: "0").toInteger() List<String> runTasks = gradle.startParameter.getTaskNames(); def value = 0 for (String item : runTasks) if ( item.contains("assembleRelease")) { value = 1; } _versionCode = (versionProps['VERSION_CODE'] ?: "0").toInteger() + value if(_patch==99) { _patch=0 _minor=_minor+1 } if(_major==99){ _major=0 _major=_major+1 } versionProps['MAJOR']=_major.toString() versionProps['MINOR']=_minor.toString() versionProps['PATCH']=_patch.toString() versionProps['VERSION_CODE']=_versionCode.toString() versionProps.store(versionPropsFile.newWriter(), null) def _versionName = "${_major}.${_versionCode}.${_minor}.${_patch}" compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { applicationId "com.yourhost.yourapp" minSdkVersion 16 targetSdkVersion 24 versionCode _versionCode versionName _versionName } 
0
Jul 09 '16 at 7:56
source share

The code for the first comment will increase the number each time the Project is rebuilt and save the value in the Version Property file.

The second comment code will generate the name of the new version of the APK file during "Build APKs".

 android { compileSdkVersion 28 buildToolsVersion "29.0.0" //==========================START================================== def Properties versionProps = new Properties() def versionPropsFile = file('version.properties') if(versionPropsFile.exists()) versionProps.load(new FileInputStream(versionPropsFile)) def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1 versionProps['VERSION_CODE'] = code.toString() versionProps.store(versionPropsFile.newWriter(), null) //===========================END=================================== defaultConfig { applicationId "com.example.myapp" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "0.19" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' //=======================================START=============================================== android.applicationVariants.all { variant -> variant.outputs.all { def appName = "MyAppSampleName" outputFileName = appName+"_v${variant.versionName}.${versionProps['VERSION_CODE']}.apk" } } //=======================================END=============================================== } } } 
0
Jul 18 '19 at 17:56
source share

in Gradle version 5.1.1 on Mac, I changed the way I get task names, although I tried to get the assembly type / type from the assembly, but I was too lazy to split the task name:

 def versionPropsFile = file('version.properties') if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) def value = 0 def runTasks = gradle.getStartParameter().getTaskRequests().toString() if (runTasks.contains('assemble') || runTasks.contains('assembleRelease') || runTasks.contains('aR')) { value = 1 } def versionMajor = 1 def versionMinor = 0 def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1 def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value versionProps['VERSION_PATCH'] = versionPatch.toString() versionProps['VERSION_BUILD'] = versionBuild.toString() versionProps['VERSION_NUMBER'] = versionNumber.toString() versionProps.store(versionPropsFile.newWriter(), null) defaultConfig { applicationId "de.evomotion.ms10" minSdkVersion 21 targetSdkVersion 28 versionCode versionNumber versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild})" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" signingConfig signingConfigs.debug } } else { throw new GradleException("Could not read version.properties!") } 

code from @just_user this

0
Jul 30 '19 at 12:09 on
source share

The above examples do not work for various reasons.

Here is my finished version, based on the ideas from this article:

 android { compileSdkVersion 28 // https://stackoverflow.com/questions/21405457 def propsFile = file("version.properties") // Default values would be used if no file exist or no value defined def customAlias = "Alpha" def customMajor = "0" def customMinor = "1" def customBuild = "1" // To be incremented on release Properties props = new Properties() if (propsFile .exists()) props.load(new FileInputStream(propsFile )) if (props['ALIAS'] == null) props['ALIAS'] = customAlias else customAlias = props['ALIAS'] if (props['MAJOR'] == null) props['MAJOR'] = customMajor else customMajor = props['MAJOR'] if (props['MINOR'] == null) props['MINOR'] = customMinor else customMinor = props['MINOR'] if (props['BUILD'] == null) props['BUILD'] = customBuild else customBuild = props['BUILD'] if (gradle.startParameter.taskNames.join(",").contains('assembleRelease')) { customBuild = "${customBuild.toInteger() + 1}" props['BUILD'] = "" + customBuild applicationVariants.all { variant -> variant.outputs.all { output -> if (output.outputFile != null && (output.outputFile.name == "app-release.apk")) outputFileName = "app-${customMajor}-${customMinor}-${customBuild}.apk" } } } props.store(propsFile.newWriter(), "Incremental Build Version") defaultConfig { applicationId "org.example.app" minSdkVersion 21 targetSdkVersion 28 versionCode customBuild.toInteger() versionName "$customAlias $customMajor.$customMinor ($customBuild)" ... } ... } 
0
Aug 29 '19 at 0:23
source share



All Articles