Python 實現Android打包並安裝後啟動
前言:
這個週末,學會了Python並寫了一個打包的指令碼,可以很方便的打包並安裝。因為剛開始使用Python,不知道Python怎麼面向物件,面向過程的寫,一個流程走下來,之後深入學習後可以寫的方便修改一點。
本文程式碼在: LearnTechDemo下00Something目錄下的auto.py
和auto.config
兩個檔案。
1. 主要功能介紹:
- 自動從Git拉取程式碼
git pull
或git clone
此過程中如果第一次執行指令碼,則需要向根目錄寫local.properties
檔案,設定SDK路徑。 - 執行打包命令
gradle clean
後gradle assembleDebug
- 自動安裝到機器
adb install
後adb shell am start -n
自動開啟
該指令碼主要功能就是這三個,看完後就有個大概認識,只要一執行,就能自動將最新apk執行到手機上並開啟。
還有些其他很方便的功能:
在指定目錄下建立
AndroidApp
,並在該目錄下建立Apk
和SourceCode
兩目錄。
Apk目錄
:打包後build
目錄下的apk檔案
拷貝一份該目錄,方便再次找到。
SourceCode目錄
:git clone的專案程式碼到該目錄下新增
auto.config
配置檔案,用來配置一些基本的路徑。使用Python的ConfigParser
包來讀取配置檔案。- 現在主要配置:
Root_SDK_Dir
: SDK的絕對路徑,用於local.properties
git_clone_address
:專案的Git地址
git_branch_name
:要拉取的遠端分支名
assembleRelease
:boolean值,是否打release包
base_file_dir
:是在哪個目錄下建立AndroidApp資料夾
create_dir_name
:就是這個AndroidApp資料夾的名字,可以設定這個更改 - 這兩個可以不設定
optional
:
create_code_dir_name
:這個SourceCode資料夾的名字
create_apk_dir_name
- 現在主要配置:
解析
manifest.xml
檔案獲取PackageName
和LauncherActivityName
。
使用ElementTree來解析xml,使用遞迴獲取到LauncherActivity的名字用於開啟app。相容了python2 和 python3。
Mac上執行的是python2,在windows上執行時又適配到python3了。
2. 使用方法
將
auto.py
和auto.config
檔案放在同一級目錄下。然後配置
auto.config
檔案:
Root_SDK_Dir
是你的SDK的絕對路徑
git_clone_address
是你的Git地址
git_branch_name
要拉取的遠端分支名
assembleRelease
boolean值,是否打release包
base_file_dir
是一個絕對路徑,可隨便填
create_dir_name
將在base_file_dir
生成一個目錄,用於存放專案程式碼和打出來的APK檔案
配置好後你就可以使用python命令列執行該指令碼,等待打包完成後執行到機器。
3. 主要程式碼介紹
1.git拉取程式碼
# 進入SourceCode目錄下
os.chdir(code_dir)
print('進入SourceCode下: ' + os.getcwd())
print('\n')
print('=============================================')
print('git clone or git pull')
print('=============================================')
if not os.listdir(code_dir):
#空資料夾
os.system('git clone ' + git_clone_address +' ' + code_dir)
else:
#已經clone過
os.system('git pull')
2.gradle打包
# 生成local.properties檔案
def createLocalPropertiesFile(sourceDir,fileName,root_sdk_dir):
if not os.path.exists(sourceDir):
return
fileDir = sourceDir + '/' + fileName
if os.path.exists(fileDir):
return
f = open(fileDir,'w');
f.write('sdk.dir=' + root_sdk_dir)
f.close()
createLocalPropertiesFile(code_dir,'local.properties',Root_SDK_Dir)
# 打包
print('\n')
print('=============================================')
print('gradle clean')
print('=============================================')
os.system('gradle clean');
print('\n')
print('=============================================')
print('gradle assembleDebug, generate apk')
print('=============================================')
os.system('gradle assembleDebug')
3.安裝apk
#安裝apk
print('\n')
print('=============================================')
print('install apk')
print('=============================================')
def getFileName(sourceDir):
if not os.path.exists(sourceDir):
return;
for filename in os.listdir(sourceDir):
if '.apk' in filename:
return filename
apkName = getFileName(apk_dir)
apkPath = apk_dir + '/' + apkName
print(apkPath)
os.system('adb install -r ' + apkPath)
4.開啟app
#獲取PackageName,launcherActivity
def findLauncherActivityName(ele,targetString):
for childElem in ele:
if len(list(childElem)) == 0:
if cmp(childElem.get('{http://schemas.android.com/apk/res/android}name'),"'" + targetString +"'"):
return True
else:
return False
else:
# print('has child, ' + childElem.tag, childElem.attrib)
return findLauncherActivityName(childElem,targetString)
def getLauncherActivity(xmlFileDir):
tree = ET.ElementTree(file=xmlFileDir)
root = tree.getroot()
packageName = root.get('package')
for elem in tree.iter(tag = 'activity'):
if findLauncherActivityName(elem,'android.intent.action.MAIN'): #if has
if(findLauncherActivityName(elem,'android.intent.category.LAUNCHER')):
return packageName,elem.get('{http://schemas.android.com/apk/res/android}name')
PackageName,LauncherActivity = getLauncherActivity(code_dir + '/app/src/main/AndroidManifest.xml')
# 先關閉該程序
os.system('adb shell am force-stop ' + PackageName)
# 開啟該LauncherActivity
if PackageName in LauncherActivity:
os.system('adb shell am start -n '+ PackageName +'/' + LauncherActivity)
else:
os.system('adb shell am start -n '+ PackageName +'/' + PackageName + LauncherActivity)
4. 缺點
該指令碼需要大量的環境配置,尤其是Gradle的配置。在打包過程中,需要一系列的工具,BuildTools、gradle plungin等,並不適合開發以外的人使用,需要學習的東西太多。
但是這個指令碼是個學習python練手的好專案。
結語
發現Python很容易上手,而且很方便。沒有分號和大括號程式碼看起來真的很清爽,字串也可以用單引號,很方便。恩,在這個過程中,發現好像 jenkins 就能很方便的做這種事,可以研究研究。
恩,希望能對大家有幫助。在使用過程中有Bug或者有更好的實現請留issue或留言。