在 AndroidStudio 工程點擊 Run 按鈕, 實際上做了什麼操作呢?
@singwhatiwanna 大神講的很詳細,我來從執行和代碼角度分析一下:通過查看AS IDE插件的源碼 解釋具體過程。
先說結論:點擊Run按鈕其實依次執行了3部分內容
- 檢查項目和讀取基本配置
- Gradle Build
- Apk Install LaunchActivity
-----------
Android Studio 本質上其實還是 Intellij IDEA ,AS對IDEA擴展的代碼放在:JetBrains/android。打包進AS之後,代碼位於:ANDROID_STUDIO/plugins/android/lib/android.jar。解壓並反編譯就可以看到源碼。
點擊Run按鈕對於IDEA來說,其實是執行一個事先配置好的 [ Run/Debug Configuration ],對於Android項目來說,往往是一個名為 [ Android App ] 的 Configuration。
按照IntellIJ SDK約定,一個Configuration的執行包括倆個過程:RunState 的創建 和 執行。
檢查項目和讀取基本配置
RunState的創建過程就對應開頭所說的 過程1,完整代碼請查看:AndroidRunConfigurationBase.java
如下圖所示,基本上完成了對項目的檢查,InstantRun相關配置,包括選擇目的機器(沒錯,就是每次都會彈出來讓你選擇機器的模態對話框。。。)等過程。
Gradle Build
在RunState創建完成之後,IDEA允許你在執行之前,執行一些任務,比如一個Java項目在運行之前,你得編譯。我們的Android項目也是類似,在安裝和部署之前,你得編譯打包。這個過程稱之為:Before Launch。
Android Studio默認為我們提供 Gradle-aware Make 。這一塊的代碼在:MakeBeforeRunTaskProvider.java
如下圖,本質上去執行了Gradle Tasks,在Debug環境下默認是assembleDebug, 如果用戶更改了Build Variants也會相應變化。
(在Configuration頁面你去修改Gradle-aware Make,改成任意Gradle任務,就可以去執行自己的Task啦...)
Apk Install LaunchActivity
在構建完成之後,會回到RunState的執行階段,這一階段應該叫做部署 : InstantRun相關邏輯,版本判斷,設備判斷,輸出日誌,調用pm命令安裝APK,喚起首屏等等。相應代碼在 AndroidRunState.java。
是不是比想像中要複雜?正如 @coxier 所說,通過命令行運行之所以有時候會快一點,是因為少了前後倆個步驟。另外,與這個問題相關的是點擊同步Gradle Sync按鈕實際上做了什麼,其實只要去翻翻代碼就瞬間明白了。
最後,官方的解釋在這:
JetBrains/android
點擊 Run 按鈕,就相當於執行了一次 Gradle Task,一般來說,是assembleDebug或者assembleRelease。
首先,點擊 Run 按鈕會執行一個配置,比如下圖中的app就是一個配置。
AS中有很多配置,比如:
這裡只說Android App這類配置,相信大家看圖也是可以理解的,無非就是指定一下module和Activity的名字。
另外,app配置具體要執行的task還和Build Variants有關,如下圖所示,這會決定到底是assembleDebug還是assembleRelease,整個過程就是這個樣子。
整個過程的log如下所示,很清楚了。
17:35:33 Executing tasks: [:app:assembleDebug]
17:35:34 Gradle build finished in 858ms
09/14 17:35:34: Launching app
$ adb push /Users/didi/github/VirtualAPK/app/build/outputs/apk/app-debug.apk /data/local/tmp/com.didi.virtualapk
$ adb shell pm install -r "/data/local/tmp/com.didi.virtualapk"
Success
$ adb shell am start -n "com.didi.virtualapk/com.didi.virtualapk.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 21777 on device samsung-sm_g9500-98895a473737504e42
其他類型的配置是如何Run的,我沒咋研究過,其他同學可以補充下。
無非就是幾個過程:
- 將代碼打包成APK,這裡面涉及到編譯、打包、簽名、混淆等;
- 安裝APK到設備;
- 在設備上運行APK。
其實就是執行一系列的gradle task,每個task需要執行的功能都已經定義好了,具體可以查看gradle console,有詳細的信息:
gradle installDebug
實際上複雜一點,比如先執行以下Gradle Sync,根據當前項目屬性和鏈接設備的類型創建一系列的構建參數,再執行構建任務,沒有什麼能比源碼更清晰的了 :MakeBeforeRunTaskProvider.java
首先會執行grade assembleDebug的task,
相當於你在命令行中輸入./gradlew assembleDebug
然後點run
$ adb push /home/shanjinwei/work/OPWeather/build/outputs/apk/debug/OPWeather-debug.apk /data/local/tmp/net.oneplus.weather
$ adb shell pm install -t -r "/data/local/tmp/net.oneplus.weather"
Success
$ adb shell am start -n "net.oneplus.weather/net.oneplus.weather.app.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
如果你開啟了instant run ide會執行命令
adb install-multiple -r -t
大概就是這個樣子
Run 和 Make Project 對比:
Run的時候,只編譯與要運行相關的代碼,無關的代碼不會檢查。
Make Project 編譯工作空間所有的項目。
比如,我們如果單元測試的代碼有問題,直接Run是不會檢查的。但是Make Project會。因為Run的時候僅執行了assembleDebug,但是跑單元測試時需要執行 assembleDebug和assembleDebugAndroidTest。
比如,我們Run MoudleA,MoudleA依賴MoudleB,MoudleA不依賴MoudleC,那麼Run MoudleA是不會檢查到MoudleC的代碼是否編譯通過。
Run一個Android的APP啟動詳細情況:
1、執行Gradle:(從AS的Gradle Console可以看到詳細的Task執行情況)
Executing tasks: [:app:assembleDebug]
2、Launching app:(從AS的run窗口查看詳細情況)
&>&>&>&> apk無更新的情況
No apk changes detected since last installation, skipping installation of E:xtcworkplaceIMappuildoutputsapkapp-debug.apk
(1)Kill當前應用
$ adb shell am force-stop com.xxx.demo
(2)啟動應用指定的Activity到指定的機器
$ adb shell am start -n "com.xxx.demo/com.xxx.demo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 5467 on device vivo-vivo_y51a-614ac269
&>&>&>&>&>&> apk有更新的情況
(1)把前面編譯好的apk包push到機器/data/local/tmp/目錄中
$ adb push E:xtcworkplaceIMappuildoutputsapkapp-debug.apk /data/local/tmp/com.xxx.demo
(2)安裝應用
$ adb shell pm install -t -r "/data/local/tmp/com.xxx.demo"
pkg: /data/local/tmp/com.xxx.demo
Success
(3)啟動應用指定的Activity到指定的機器
$ adb shell am start -n "com.xxx.demo/com.xxx.demo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 7364 on device vivo-vivo_y51a-614ac269
Make Project 詳細情況:
[ :moudule1:generateDebugSources,
:moudule1:generateDebugAndroidTestSources,
:moudule1:mockableAndroidJar,
:moudule1:prepareDebugUnitTestDependencies,
:moudule1:compileDebugAndroidTestSources,
:moudule1:compileDebugUnitTestSources,
:moudule1:compileDebugSources,
:app:generateDebugSources,
:app:generateDebugAndroidTestSources,
:app:mockableAndroidJar,
:app:prepareDebugUnitTestDependencies,
:app:compileDebugAndroidTestSources,
:app:compileDebugUnitTestSources,
:app:compileDebugSources]
主要執行了上述幾個task。
上述回答中,Build Variant 為 debug。
對於像我對gradle不是很熟悉的同學,可以這樣理解 debug 模式下的 run。
- Android Studio 提供了 GUI 圖形界面,那個 run 按鈕點擊後,會執行一個腳本
- 腳本運行的實質應該是執行了兩個主要任務:assembleDebug 和 installDebug
對於項目大了之後,一般都不點擊 run 按鈕了,改用腳本執行這兩個任務,因為太慢了(猜測做了一些hook)。
別用IDE,只用命令行下的vim和gradle的命令,你就知道幹了什麼了。
起碼你會自己寫build.gradle 然後 gradle build 。然後就生成了apk文件。然後adb install安裝到測試手機。然後 adb shell am start 啟動到相應的activity。然後adb logcat再看日誌。
推薦閱讀:
TAG:Android | Gradle | AndroidStudio |