Freeline極速增量編譯工具詳細(xì)文檔

Freeline極速增量編譯工具詳細(xì)文檔

Freeline 是一款 Android 平臺上的秒級編譯方案,能夠顯著地提高 Android 工程的比較大,moudle較多時候的編譯速度

舉個具體的栗子:

公司當(dāng)前的項目23M左右,包括user ,主項目 core ,定期,活期,基金等幾個moudle,修改代碼重新編譯運行大概需要5分鐘左右;使用了freeline 第一次可能需要十分鐘左右的一個全量編譯。使用了freeline 基本每次編譯運行在20s左右。

Google 推出了官方的 Instant Run這個方案有太多的 case 無法覆蓋,甚至在一些比較大型的工程上基本上無法使用。Freeline 從本質(zhì)上來說是 Gradle 構(gòu)建系統(tǒng)上的 hack 解決方案,所以對于多種多樣的 Android 工程可能還存在著一些兼容性問題

freeline 支持的場景

支持標(biāo)準(zhǔn)的多模塊 Gradle 工程的增量構(gòu)建
并發(fā)執(zhí)行增量編譯任務(wù)
進(jìn)程級別異常隔離機制
支持 so 動態(tài)更新
支持 resource.arsc 緩存
支持 retrolambda
支持 DataBinding
支持各類主流注解庫(APT)
支持 Windows,Linux,Mac 平臺

freeline 的使用

接入前的準(zhǔn)備

Windows 用戶,你需要提前安裝 Python 2.7+(Freeline 暫時還不支持 Python 3+),安裝完之后需要重啟一下 Android Studio
Linux/Mac 用戶,如果你已經(jīng)安裝了 Python 3+,推薦你將其 alias 設(shè)為 python3,再單獨安裝 Python 2.7+,并作為默認(rèn)的 Python 指令,避免與 Android Studio 插件自動運行的 python 命令沖突,導(dǎo)致無法正常使用插件。

freeline 接入

目前驗證的接入方法,使用了兩種:

1.使用Android studio 插件直接接入

在最新版本的 Freeline 插件中,提供了自動化一鍵接入的方式,不需要像以前一樣手動修改build.gradle配置文件了。

在AS中:

通過以下路徑Preferences → Plugins → Browse repositories,搜索“freeline”,并安裝。 安裝好了重啟AS。

[圖片上傳失敗...(image-819665-1511943160043)]

直接點擊 Run Freeline的按鈕,就可以享受Freeline帶來的開發(fā)效率的提升啦(當(dāng)然,你可能會先需要一個較為耗時的全量編譯過程)。

在這個過程,你會發(fā)現(xiàn)他默認(rèn)給你加上了依賴 就是我們方法2的依賴

第一次使用的時候,插件會自動檢測是否安裝了 Freeline,如果沒有安裝的話會彈出提示,按照提示點擊“確定”,插件就會自動為你修改配置文件,并自動安裝 Freeline 的依賴文件。

2.使用命令行方式接入

1.在項目的 build.gradle,加入 freeline-gradle 的依賴: (依賴的最新版本,可以直接GitHub 上搜索freeline 查看)

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        ...
        classpath 'com.antfortune.freeline:gradle:0.8.8'
    }
}

2.在主項目的build.gradle 中加上

apply plugin: 'com.antfortune.freeline'

在命令行執(zhí)行以下命令來下載 freeline 的 python 和二進(jìn)制依賴。

Windows[CMD]: gradlew initFreeline

Linux/Mac: ./gradlew initFreeline

上面的命令我驗證翻墻也不能下載,window 下直接使用:gradlew initFreeline -Pmirror 能夠編譯成功

freeline 常規(guī)使用:

使用方式:

image.png

安裝完了這個freline 插件,在AS底部有這框了,然后點下,跟我們的日志窗口類似,然后看下,從上到下,分別是快速編譯,停止,全量編譯,我們一般為了保證成功率,先點擊下停止,在點第一個快速編譯,這樣,就能free!!!!

接入的注意事項:

1、debug 模式下不要開啟混淆
2、如果有渠道包,多個 productFlavor 的話,需要配置指定 flavor
3、首次執(zhí)行如果卡住了,

運行的時候出現(xiàn)了耗時長達(dá)十幾分鐘的話,需要注意一下是否卡在下載 gradle 文件了。檢查的方法即手動執(zhí)行 gradlew checkBeforeCleanBuild。如果是卡在下載 gradle 文件的話,可以查找一下網(wǎng)絡(luò)上相關(guān)的資料看下如何解決這個問題。

其他更多關(guān)于 Freeline DSL 的使用,可以參考 Freeline DSL References。

4.freeline 使用禁忌:

第一次增量資源編譯的時候可能會有點慢,因為需要額外傳遞一個完整的資源包
不支持刪除帶id的資源,否則可能導(dǎo)致aapt編譯出錯
暫不支持抽象類的增量編譯(V 0.8.8)
部分 APT 插件可能需要單獨適配
絕大部分 APT 插件還是都支持的
不支持開啟 Jack 編譯
想要使用 lambda 的話,先使用 Retrolambda 吧
不支持 Kotlin / Groovy / Scala
能夠支持這幾個基于 JVM 的語言的工具叫做 JRebel for Android,你可以看看

freeline升級

在 Android Studio 中通過以下路徑:Build → Freeline → Check Freeline Update即可自動檢測新版本,點擊update按鈕,插件會自動為你進(jìn)行升級。

當(dāng)然,你也可以使用命令行的方式來升級 Freeline,修改方法如下:

修改 project-level 的build.gradle文件,將classpath ‘com.antfortune.freeline:gradle:x.x.x’修改為最新版本

在命令行中執(zhí)行(國內(nèi)的同學(xué)推薦加上-Pmirror參數(shù)):

Windows[CMD]: gradlew initFreeline

Linux/Mac: ./gradlew initFreeline

Gradle Task: checkBeforeCleanBuild

原理(摘至官網(wǎng))

Freeline 本質(zhì)上是熱更新技術(shù)在編譯期的運用,通過對同一個 apk 進(jìn)行持續(xù)地?zé)岣聛磉_(dá)到增量編譯的效果。基于 Freeline 進(jìn)行修改,也能夠?qū)崿F(xiàn)線上應(yīng)用的熱修復(fù)以及 A/B Test。

Freeline 與其他類似的加速構(gòu)建方案,比如 Instant Run、Buck、JRebel for Android 有什么區(qū)別呢?開發(fā)者如何來選擇加速構(gòu)建方案呢?可以參考這個知乎回答:有什么辦法能加快Android Studio中Gradle build速度? - Yong Huang 的回答 - 知乎。

Gradle Task: initFreeline

主要用于下載 freeline 的二進(jìn)制依賴(包括 python 文件等)和生成工程描述文件。

在 build.gradle 中應(yīng)用了 freeline gradle 插件之后,initFreeline這個任務(wù)會被添加到 Gradle 工程的根工程上,可以執(zhí)行g(shù)radlew initFreelien來執(zhí)行這個任務(wù)。

我們也為 initFreeline 這個任務(wù)提供了多種參數(shù)方便開發(fā)者們做一些定制化的修改。

參數(shù):

mirror

使用方法:gradlew initFreeline -Pmirror

參數(shù)說明:將下載鏈接指向國內(nèi)鏡像。不加參數(shù)的時候,默認(rèn)從 aws 上進(jìn)行下載,如果你所處的網(wǎng)絡(luò)環(huán)境訪問 aws 有問題的話,加上這個參數(shù)可以讓你獲得更好的下載速度。

freelineVersion

使用方法:gradlew initFreeline -PfreelineVersion=0.8.2

參數(shù)說明:下載指定版本的 freeline 依賴文件。注意,使用這個參數(shù)的時候,請務(wù)必保證 build.gradle 文件中配置的 freeline 版本與指定要下載的 freeline 版本的版本號是一致的,以免產(chǎn)生一些不必要的編譯錯誤。

freelineTargetUrl

使用方法:gradlew initFreeline -PfreelineTargetUrl=”http://xxx.com/freeline.zip

參數(shù)說明:從指定的鏈接處下載 freeline 依賴文件。

freelineCdnUrl

使用方法:gradlew initFreeline -PfreelineCdnUrl=”http://xxx.com

參數(shù)說明:使用指定的鏡像處下載,適合訪問外網(wǎng)需要白名單,在內(nèi)網(wǎng)自己搭建鏡像的同學(xué)使用

freelineLocal

使用方法:gradlew initFreeline -PfreelineLocal=”your-local-freeline-path”

參數(shù)說明:使用已經(jīng)下載好的 freeline 依賴文件來安裝,參數(shù)指向下載好的 freeline 依賴文件的本地路徑。

主要用于生成工程描述文件,每次 freeline 全量編譯前會先執(zhí)行一下這個任務(wù)。當(dāng)你執(zhí)行 python 命令提示報錯的時候:freeline_core.exceptions.NoConfigFoundException: xxxxxx/project_description.json not found, please execute gradlew checkBeforeCleanBuild first.,也需要先執(zhí)行一下gradlew checkBeforeCleanBuild。

Gradle Build

freeline 為了不污染日常編譯的編譯產(chǎn)物,在執(zhí)行g(shù)radlew assemble之類的編譯命令時,不會啟動 freeline 植入的任務(wù)。如果你想要在命令行運行 freeline 的任務(wù),查看 freeline 輸出的日志的話,需要在編譯命令中,加入?yún)?shù)-PfreelineBuild=true。

freeline gradle 插件會在編譯時,自動為工程加入 freeline 的 runtime 依賴(對于 release、test 版本自動加入 no-op 版本),如果你希望能夠?qū)?freeline runtime 的源碼引入到工程中的話,需要在 freeline DSL 中加入配置,如:

freeline {

autoDependency false

}

然后使用 freeline 重新進(jìn)行編譯。如果要手動在命令行進(jìn)行編譯的話,需要加入?yún)?shù):-PdisableAutoDependency=true。

freeline.py

使用 freeline 進(jìn)行編譯的主要入口,freeline 主要通過 python 來實現(xiàn)跨平臺。

參數(shù):

-h

使用方式:python freeline.py -h

參數(shù)說明:輸出 freeline 的參數(shù)使用說明

-v

使用方式:python freeline.py -v

參數(shù)說明:獲取 freeline.py 的版本號

-f

使用方式:python freeline.py -f

參數(shù)說明:強制進(jìn)行全量編譯

-d

使用方式:python freeline.py -d(注:可與各類參數(shù)疊加使用)

參數(shù)說明:輸出 freeline 的調(diào)試日志(注意:不是對 Android 工程進(jìn)行調(diào)試)

-w

使用方式:python freeline.py -f -w

參數(shù)說明:讓應(yīng)用啟動的時候等待調(diào)試工具連接(目前只支持全量編譯的時候配合使用),日常調(diào)試推薦直接使用 Android Studio 的attach debugger to Android process

Freeline DSL

Freeline DSL 用來輔助進(jìn)行工程配置,幫助 freeline 與 Android 工程無縫集成。主要配置在 Android 的主 module 的 build.gradle 文件中,形如:

android {

freeline {
    ... // 具體的配置內(nèi)容
}

}

注意,當(dāng)涉及到在配置中定位具體的文件路徑的時候,為了便于團隊協(xié)作共同使用同一份 build.gradle 配置文件,推薦使用類似這樣的方式,來書寫文件路徑:project.rootProject.file(“your-relative-path”).getAbsolutePath()

以下為具體的配置的說明:

hack

引入版本:0.5.0,目前已廢棄

參數(shù)類型:boolean

默認(rèn)值:false

參數(shù)說明:是否使用 freeline 來打包的全局開關(guān)

buildScript

引入版本:0.5.0

參數(shù)類型:String

默認(rèn)值:gradlew :main_module:assemble{ProductFlavor}Debug

參數(shù)說明:工程的全量編譯腳本,freeline 在全量打包時使用這個命令腳本來編譯出 apk 產(chǎn)物

productFlavor

引入版本:0.5.0

參數(shù)類型:String

默認(rèn)值:””

參數(shù)說明:當(dāng)工程含有多個 productFlavor 的時候,需要指定一個 flavor。如果未指定 flavor,則可能造成編譯失敗報錯退出,會有錯誤日志引導(dǎo)添加這個配置參數(shù)

apkPath

引入版本:0.5.0

參數(shù)類型:String

默認(rèn)值:freeline 會在編譯過程中自動去找到編譯產(chǎn)物 apk 的路徑

參數(shù)說明:編譯產(chǎn)物 apk 的路徑,freeline 也有可能找到錯誤的編譯產(chǎn)物路徑,這個時候可以手動配置正確的路徑參數(shù)

extraResourceDependencyPaths

引入版本:0.5.0

參數(shù)類型:List[String]

默認(rèn)值:[]

參數(shù)說明:額外的工程的資源依賴路徑。如果使用 freeline 編譯的過程中出現(xiàn)了 aapt 編譯報錯,提示資源沒找到,有可能是某些資源路徑未被 freeline 自動檢測到,這時可以將缺失的資源路徑添加到這個參數(shù)中。注意,資源路徑只需要添加到 res 一級即可,不需要具體到 drawable/layout/.xml/.drawable 這樣的路徑

excludeResourceDependencyPaths

引入版本:0.5.0,已不需要

參數(shù)類型:List[String]

默認(rèn)值:[]

參數(shù)說明:排除會導(dǎo)致重復(fù)的資源路徑。后期的版本中,通過對 aapt 的修改,繞過了這個問題,已不需要這個參數(shù)

excludeHackClasses

引入版本:0.5.0

參數(shù)類型:List[String]

默認(rèn)值:[]

參數(shù)說明:打包過程中,freeline 會對 class 進(jìn)行插樁,默認(rèn)會跳過父類為android/app/Application的類。如果你有特殊需求需要繞過插樁,可以通過這個配置項進(jìn)行配置

packageName

引入版本:0.5.5

參數(shù)類型:String

默認(rèn)值:applicationId

參數(shù)說明:freeline 默認(rèn)獲取 applicationId 作為應(yīng)用的包名。如果你有特殊需求,或者 freeline 獲取到了錯誤的包名的話,可以通過這個配置項配置你指定的包名

launcher

引入版本:0.5.5

參數(shù)類型:String

默認(rèn)值:””

參數(shù)說明:freeline 默認(rèn)從 AndroidManifest.xml 文件中去獲取應(yīng)用的 launcher Activity,并用于全量編譯后自動啟動應(yīng)用。如果 freeline 獲取的 launcher 有誤的話,可以通過這個配置項配置你指定的 launcher

applicationProxy

引入版本:0.7.0

參數(shù)類型:boolean

默認(rèn)值:true

參數(shù)說明:為了便于快速集成,freeline 默認(rèn)會替換應(yīng)用的 Application 類,替換為 FreelineApplication。如果由于這個替換造成了 ClassNotFound 等問題,可以將這里的值置為 false,并手動在你的 Application 類中加入FreelineCore.init(this);。修改后,進(jìn)行編譯之前,記得先 clean,然后再來編譯,避免無謂的錯誤出現(xiàn)

autoDependency

引入版本:0.7.0

參數(shù)類型:boolean

默認(rèn)值:false

參數(shù)說明:freeline 自動為應(yīng)用加載了 runtime 依賴,在非 debug 的 buildType 加載的是 no-op 版本,如果你希望通過引源碼的方式來加入 runtime 依賴,或者手動指定 runtime 的版本,需要將此配置項置為 true,然后再來手動加入依賴

如何進(jìn)行斷點調(diào)試?

使用 freeline 進(jìn)行調(diào)試跟平時調(diào)試基本上是一樣的。推薦選擇 Android Studio 工具欄上的attach debugger to Android process即可進(jìn)行斷點調(diào)試。如果需要在 Application 的邏輯中進(jìn)行調(diào)試的話,可以使用命令python freeline.py -f -w,工程會在全量編譯結(jié)束啟動時,自動等待 debugger 工具的連接。

注意:python freeline.py -d僅僅是輸出 freeline 的調(diào)試日志而已,并不是真的在對 Android 工程進(jìn)行調(diào)試。

是否支持 Kotlin、Groovy、Scala 等 JVM 語言?

不支持。Freeline 基于

.java -> .class -> *.dex這樣的編譯鏈進(jìn)行編譯,并通過 multidex 的方案進(jìn)行增量。故無法支持除 Java 之外的其他 JVM 語言。

是否可以開啟 Jack 來使用 Java 8 的特性?

不支持,原因同上,Jack 改變了編譯鏈(.java –> .jack –> *.dex)。

是否會影響 release 打包?

Freeline 對 release 打包幾乎沒有影響。Freeline 在 release 打包的時候自動添加的是no-op的 runtime 依賴,對FreelineCore.init(this);函數(shù)是一個空實現(xiàn)。如果你開啟了 Application 代理的話,更是基本上毫無影響,請放心使用。

如果你還是實在放心不下的話,可以在打 release 包的時候,把 freeline 相關(guān)的內(nèi)容注釋掉,然后 clean and build。

為什么 Freeline 會進(jìn)行全量編譯?

Freeline 在以下幾種情況下會自動進(jìn)行全量編譯:

發(fā)現(xiàn) AndroidManifest.xml 有修改

發(fā)現(xiàn) build.gradle 文件有修改

發(fā)現(xiàn)有超過 20 個 Java 文件有修改過(通常在使用 git 切換分支的情況會出現(xiàn))

不停地提示 check sync status failed /不停地全量編譯?

以下操作建議使用python freeline.py -d命令來查看詳細(xì)日志:

通常,freeline 在全量編譯后,會自動進(jìn)行增量編譯,但是在以下幾種情況下,會從增量轉(zhuǎn)入全量編譯:

涉及到 build.gradle、settings.gradle、AndroidManifest.xml 文件有改動

增量編譯時,發(fā)現(xiàn)有超過 20 個 java 文件出現(xiàn)改動

也有一種情況,每次都出現(xiàn)一句日志:[WARNING] check sync status failed, a clean build will be automatically executed.

這句日志的意思是,通過 adb 連接上的設(shè)備上找到了與本地編譯的項目相同 uuid 的應(yīng)用(通常是同個項目使用 freeline 打包安裝上的),但是在進(jìn)行基線校驗的時候校驗失敗,需要重新打包編譯。Freeline 的基線校驗值由 apk 打包的時間與增量次數(shù)共同生成,用于保證本地編譯的版本與設(shè)備上安裝的版本是完全一致的。主要是在切換設(shè)備的時候,容易出現(xiàn)這個問題。

正常情況下,一次全量編譯后就會恢復(fù)正常,但也有可能會反復(fù)出現(xiàn)這句日志,一直無法恢復(fù)增量編譯,這種時候首先需要檢查一下 PC 上是否連接了多臺設(shè)備,或者 Android 模擬器 + 真實設(shè)備。如果有的話,首先保持只有一臺設(shè)備或者模擬器。

如果還是反復(fù)出現(xiàn)這個日志的話,可以嘗試把手機上的 apk 先卸載了,再重新用 freeline 編譯安裝。(如果是這個原因的話,可能是 freeline 的緩存不更新的 bug 導(dǎo)致的,近期會解決)

Freeline “try to connect device/ connect_device_task failed.”

排查方法如下(建議配合使用python freeline.py -d):

確定FreelineCore.init(this);加入到 Application 類中,且在onCreate()下的第一行,不要根據(jù)是否在主進(jìn)程做特殊處理,否則可能導(dǎo)致FreelineService無法正常啟動;[Freeline 0.7.0+ 開始,默認(rèn)開啟了 Application 替換,這條可以不用檢查]

確定FreelineService以及 freeline 相關(guān)組件是否正常 merge 到最終的 manifest 中,最終的 manifest 路徑在${module}/build/intermediates/manifests中;

確定python freeline.py -v與定義在 build.gradle 中的 freeline 的版本是否一致;

確定是否剛剛執(zhí)行了清空app數(shù)據(jù)的操作,freeline 緩存數(shù)據(jù)在/data/data路徑,清空app數(shù)據(jù)也會導(dǎo)致連接不上的問題(執(zhí)行 freeline 命令時,通常會有句明顯的日志反復(fù)出現(xiàn):server result is -1);

確定是否開啟了網(wǎng)絡(luò)代理導(dǎo)致127.0.0.1被重定向?

一定要先使用 freeline 來打全量包,再來進(jìn)行增量,否則也會出現(xiàn)這個問題。即,freeline 的全量編譯與android-studio自帶的RUN會存在沖突。

當(dāng)上述問題都無法解決時,有個終極的解決方案就是重啟試試…不少人通過重啟順利解決連接不上的問題。。。

java.lang.UnsupportedClassVersionError: com/android/build/gradle/AppPlugin : Unsupported major.minor version 52.0

問題原因,從 Android Studio 2.2 開始,默認(rèn)使用內(nèi)置的 Java8 版本,如果你的系統(tǒng)環(huán)境變量中使用的還是 Java7 的話,就會出現(xiàn)這個問題,解決方案就是升級系統(tǒng)的 Java 版本。

資源編譯出錯:Public symbol xxxx declared here is not defined.

Aapt 打資源包報錯。在aapt的參數(shù)中,缺少某些未被freeline自動識別的資源路徑,導(dǎo)致部分資源id沒有被找到。

解決方案,將缺少的資源路徑,在build.gradle的freeline DSL中加入配置項,如:

freeline {

extraResourceDependencyPaths = [‘/path/to/resource/directory1’, ‘/path/to/resource/directory2’]

}

注意,只需添加到res路徑即可,不需要具體到drawable、layout的具體路徑

為什么一啟動就 crash 報錯 NoClassDefFoundError?

修改一下 build.gradle 文件,添加配置項:

freeline {

applicationProxy false

}

在你的Application類中加入:

public class YourApplication extends Application {

public onCreate() {
     super.onCreate();
     FreelineCore.init(this);
}

}

然后clean,重新打包即可解決問題。

切換回 Android Studio 的 RUN 時,編譯出錯

正常現(xiàn)象。推薦先執(zhí)行g(shù)radlew clean后,再使用 Android Studio 的 RUN,就可以恢復(fù)正常了。

報錯:NoConfigFoundException

提示如:NoConfigFoundException:/path/ not found, please execute gradlew checkBeforeCleanBuild first.

terminal 執(zhí)行指令:

Linux/Mac: ./gradlew checkBeforeCleanBuild

Windows: gradlew.bat checkBeforeCleanBuild

與Genymotion自帶的adb發(fā)生沖突

$ adb devices

adb server is out of date. killing…

cannot bind ‘tcp:5037’

ADB server didn’t ACK

failed to start daemon
問題出現(xiàn)的原因是 Genymotion 自帶了 adb 工具,會造成沖突。解決的方式是將 Genymotion 所使用的 adb 改為 androidsdk 自帶的 adb。具體可以參考:StackOverflow - How to use adb with genymotion on mac?

manifest merge 報錯

提示如:Exception: manifest merger failed: uses-sdk:minSdkVersion can not be smaller than 14 declared in library[com.antfortune.freeline:runtime:x.x.x]

工程的 minSdkVersion 比 freeline-runtime 來得低導(dǎo)致的,解決方案如下:

Windows 上為什么沒有類似 Linux/Mac 上的進(jìn)度條?

Freeline 在 Windows 上默認(rèn)開啟 debug 模式,輸出 debug output 信息,原因是 Windows CMD 的 terminal API 無法實現(xiàn)類似的進(jìn)度條的功能,如果你知道如何實現(xiàn)的話,也歡迎給我們提交 PR :)

為什么一直卡在“build increment app”頁面?

可以搜一下 Github 上相關(guān)的 issue,基本都是與你自己的工程或者機器的環(huán)境有關(guān)。神方法:重啟試試。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 參考:https://github.com/alibaba/freeline/blob/master/freeli...
    才兄說閱讀 6,517評論 1 9
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,264評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 雖然我們的目標(biāo)是追求卓越,但是行動的步驟卻是在固定時間,固定成本的前提下盡可能做好而已。只要我們保證下一次比現(xiàn)在更...
    Matrix101閱讀 224評論 0 0
  • 在讀幼師期間,我有一個朋友,她非常的漂亮!她很愛美、也喜歡別人關(guān)注她,但每每有人評論她這個不好、那個不好時,她...
    小小怪有個帥啊壩閱讀 347評論 9 8