Android打包—Ant

最近在項(xiàng)目中遇到了一些打包的問(wèn)題讯柔,順便去了解了下打包的一些知識(shí)點(diǎn)抡蛙。這里主要介紹和總結(jié)了一下ant、build.xml的知識(shí)點(diǎn)以及構(gòu)建apk和jar包的一些注意事項(xiàng)魂迄。

Android打包

對(duì)工程代碼和資源文件使用打包工具進(jìn)行編譯粗截、混淆、簽名捣炬、優(yōu)化對(duì)齊等一系列步驟之后生成可發(fā)布到應(yīng)用市場(chǎng)的apk的構(gòu)建過(guò)程熊昌。

打包流程

build.png

大概分為以下幾個(gè)步驟
1、使用aapt工具將res資源文件生成R.java文件
2湿酸、使用aidl工具將aidl文件生成對(duì)應(yīng)java文件
3婿屹、使用javac命令編譯工程源代碼和上面兩步生成的文件,生成class文件
4稿械、通過(guò)dex工具將class文件和第三方j(luò)ar包打成dex文件
5选泻、用aapt工具將res下的資源文件編譯成二進(jìn)制文件,然后將其和上一步中的dex文件以及assets中的文件通過(guò)apkbuilder工具打包成apk文件
6美莫、通過(guò)jarsigner對(duì)apk進(jìn)行簽名
7、利用zipalign工具對(duì)apk進(jìn)行字節(jié)對(duì)齊優(yōu)化操作

打包方式 — Ant

Ant是將軟件編譯梯捕、測(cè)試厢呵、部署等步驟聯(lián)系在一起自動(dòng)化構(gòu)建工具,主要用在java工程的構(gòu)建中傀顾,所以也可以用來(lái)進(jìn)行android打包襟铭。

現(xiàn)在android開(kāi)發(fā)工具基本上都用的AS,構(gòu)建用gradle短曾,由于某些原因寒砖,項(xiàng)目組中用的還是eclipse+ant方式,所以暫時(shí)只介紹ant的構(gòu)建方式嫉拐。雖然工具不一樣哩都,但是整個(gè)構(gòu)建原理和流程還是一樣的。

Ant的默認(rèn)構(gòu)建文件為build.xml婉徘,輸入ant命令后漠嵌,ant會(huì)在當(dāng)前目錄下搜索是否有build.xml,如果有盖呼,則執(zhí)行該文件,也可以自定義構(gòu)建文件儒鹿,通過(guò)ant -f test.xml即可指定test.xml為構(gòu)建文件。

build.xml腳本

先看一個(gè)簡(jiǎn)單的build.xml

<?xml version="1.0" encoding="GBK"?>

//ant默認(rèn)構(gòu)建文件即build.xml文件中需定義一個(gè)唯一的項(xiàng)目(Project標(biāo)簽)几晤,Project下可以定義若干個(gè)目標(biāo)(target標(biāo)簽)
//project名稱為MyApp, default表示默認(rèn)的運(yùn)行target约炎,為必須屬性,如果ant命令沒(méi)有指定target時(shí)蟹瘾,則運(yùn)行default屬性中的target
//如MyApp工程目錄下直接輸入ant命令圾浅,則會(huì)直接打debug包墙贱。 basedir表示項(xiàng)目的基準(zhǔn)目錄
<project name="MyApp" default="debug" basedir=".">

//property標(biāo)簽用來(lái)設(shè)置屬性值,可以通過(guò)file標(biāo)簽來(lái)指定要加載的屬性文件的路徑贱傀,加載后屬性文件中的指定的屬性可以直接引用惨撇。
//為了方便配置,可以將環(huán)境變量聲明在build.properties中府寒,并通過(guò)file引入到build.xml中
  <property file="build.properties"></property>

//property中的name表示屬性的名稱 value表示屬性值 在其他地方可以通過(guò)${屬性名}進(jìn)行引用魁衙, 類似于定義一個(gè)變量
  <property name="outdir" value="bin" />

//tartget,表示一個(gè)構(gòu)建目標(biāo),也可以看成一個(gè)構(gòu)建步驟株搔, 一次構(gòu)建過(guò)程中會(huì)執(zhí)行一個(gè)或者多個(gè)構(gòu)建步驟剖淀。
//target中的depends屬性表示target之間的依賴關(guān)系,一個(gè)target可以依賴其他的target標(biāo)簽纤房,depends屬性也指定了target的執(zhí)行順序纵隔。
//ant會(huì)按照depends屬性中target的順序來(lái)依次執(zhí)行每個(gè)target。所以本文中target的執(zhí)行順序?yàn)?targetone -> targettwo -> debug
  <target name="targetone">
  //創(chuàng)建目錄
    <mkdir dir="${outdir}"/>
  </target>

//task是target中的子元素炮姨,一個(gè)target中可以有多個(gè)task捌刮,類似于target的子任務(wù),常用的task有echo舒岸、mkdir绅作、delete、javac蛾派、java等等
  <target name="targettwo" depends="targetone">
  //刪除目錄
    <delete dir="${name}"/>
  </target>

  <target name="debug" depends="targettwo">
     //輸出日志信息
     <echo>debug target perform...</echo>
  </target>
</project>

打包成apk

build腳本中俄认,一般android源工程打包成apk的執(zhí)行步驟大體如下:
gen-R->aidl->compile->obfuscate->dex->package-res-and-assets->package->jarsigner->zipalign->release

gen-R之前還有一些clean清除上次打包產(chǎn)生的文件的操作,這里不再贅述
1洪乍、gen-R

 <target name="gen-R" depends="dirs">
        <exec executable="${aapt}" failonerror="true">
            <arg value="package" />
            <arg value="-m" />
            <arg value="-J" />
            <arg value="${gen-dir}" />
            <arg value="-M" />
            <arg value="${manifest-xml}" />  
            <arg value="-S" />
            <arg value="${resource-dir}" />
            <arg value="-I" />
            <arg value="${android-jar}" />
        </exec>
    </target>

gen-R 執(zhí)行aapt命令來(lái)編譯資源文件生成R.java文件 arg中的參數(shù)就是aapt中的命令行參數(shù)眯杏,該target其實(shí)執(zhí)行的就是如下命令
aapt package -m -J gen -M AndroidManifest.xml -S res -I android.jar
具體參數(shù)命令含義如下:
-m 使生成的包的目錄放在-J參數(shù)指定的目錄。
-J 指定生成的R.java的輸出目錄
-M AndroidManifest.xml的路徑
-S res文件夾路徑
-I 某個(gè)版本平臺(tái)的android.jar的路徑

2壳澳、aidl

    <target name="aidl" depends="dirs">
        <apply executable="${aidl}" failonerror="true">
            <arg value="-p${android-framework}" />
            <arg value="-I${srcdir}" />
            <arg value="-o${gen-dir}" />
            <fileset dir="${srcdir}">
                <include name="**/*.aidl" />
            </fileset>
        </apply>
    </target>

此步驟主要是生成aidl文件對(duì)應(yīng)的java文件
使用apply標(biāo)簽可以進(jìn)行批量運(yùn)行task岂贩,此步驟即用build-tools下的aidl工具對(duì)src文件夾下的所有aidl文件進(jìn)行批量轉(zhuǎn)換成java文件。
<apply>是作為<exec>的一個(gè)子類而被實(shí)現(xiàn)钾埂,所以<exec>任務(wù)的所有屬性河闰,都可以用于<apply>

3、compile

    <target name="compile" depends="dirs, gen-R, aidl">
     //javac標(biāo)簽用于編譯java文件生成class文件 destdir表示生成class文件的目錄
        <javac encoding="UTF-8" target="1.5" debug="true" extdirs="" destdir="${outdir-classes}" 
           bootclasspath="${android-jar}" fork="true"  memoryMaximumSize="512m" >
            <src path="${srcdir-ospath}" />
            <src path="${gen-dir-ospath}" />
             //表示依賴庫(kù)的路徑 內(nèi)嵌在<javac>褥紫、<java>中
            <classpath>
                <fileset dir="${external-libs}" includes="*.jar" />
            </classpath>
        </javac>
    </target>

compile執(zhí)行的是javac命令姜性,編碼格式指定為utf-8,target指定生成的class文件與該版本的虛擬機(jī)兼容髓考,保證在該版本的虛擬機(jī)上正常運(yùn)行部念。
debug表示是否產(chǎn)生調(diào)試信息,默認(rèn)為false。extdirs為擴(kuò)展文件的路徑儡炼,destdir指定了存放編譯后的class文件的文件夾路徑妓湘。bootclasspath指定了編譯過(guò)程中需要導(dǎo)入的class文件。fork指定是否再外部啟用一個(gè)新的JDK編譯器來(lái)執(zhí)行編譯乌询,如果為false榜贴,則javac命令和ant將在同一個(gè)進(jìn)程中執(zhí)行,并且javac命令被分配的內(nèi)存只有64MB妹田,可能會(huì)導(dǎo)致java.lang.OutOfMemoryError(OOM)錯(cuò)誤唬党,如果fork為true,則另起一個(gè)進(jìn)程來(lái)執(zhí)行javac命令鬼佣,分配的內(nèi)存大小將由memoryMaximumSize來(lái)指定驶拱。src指定了java源文件的路徑,classpath指定了依賴的第三方j(luò)ar包路徑晶衷。

4蓝纲、obfuscate

    <target name="obfuscate" depends="compile">
         //jar標(biāo)簽用來(lái)生成jar文件,basedir表示需要打包城jar文件的原文件目錄晌纫, destfile表示生成的jar文件
        <jar basedir="${outdir-classes}" destfile="${outdir}/temp.jar"/>
         //java標(biāo)簽用來(lái)執(zhí)行編譯生成的class文件  fork表示再一個(gè)新的虛擬機(jī)中運(yùn)行該類  failonerror表示當(dāng)出現(xiàn)錯(cuò)誤時(shí)是否自動(dòng)停止
        <java jar="${proguard.home}/proguard.jar" fork="true" failonerror="true">
             //arg標(biāo)簽用來(lái)指定參數(shù) value是命令行參數(shù)
            <arg value="-injars ${outdir}/temp.jar"/>
            <arg value="-outjars ${outdir}/obfuscate.jar"/>
            <arg value="-libraryjars ${android-jar}"/>
            <arg value="-libraryjars ${third_part_jar}"/>
            <arg value="@${proguard.config}"/>
        </java>
        <delete file="${outdir}/temp.jar"/>
        <delete dir="${outdir-classes}"/>
        <mkdir dir="${outdir-classes}"/>
        <unzip src="${outdir}/obfuscate.jar" dest="${outdir-classes}"/>
        <delete file="${outdir}/obfuscate.jar"/>
    </target>

obfuscate混淆先是執(zhí)行了jar命令税迷,將bin目錄下的class文件打包成temp.jar。然后執(zhí)行了proguard命令來(lái)壓縮缸匪、優(yōu)化和混淆操作翁狐。
-injars {class_path}指定要處理的應(yīng)用程序jar和目錄,即temp.jar
-outjars {class_path}指定處理完后要輸出的jar和目錄,即obfuscate.jar
-libraryjars {classpath}指定要處理的應(yīng)用程序jar和目錄所需要的程序庫(kù)文件,即其他依賴的第三方j(luò)ar包
混淆配置文件為proguard.config凌蔬。混淆之后刪除生成的臨時(shí)文件闯冷,并解壓obfuscate.jar到bin目錄下

5砂心、dex

 <target name="dex" depends="compile, obfuscate">
        <apply executable="${dx}" failonerror="true" parallel="true">
            <arg value="--dex" />
            <arg value="--output=${intermediate-dex-ospath}" />
            <arg path="${outdir-classes-ospath}" />
            <fileset dir="${external-libs}" includes="*.jar" />
        </apply>
    </target>

dex就是用dx.bat工具將class文件轉(zhuǎn)換成classes.dex文件,即對(duì)上一步在bin/classes目錄中生成的優(yōu)化過(guò)的class文件以及依賴的第三方j(luò)ar包進(jìn)行dex操作蛇耀,最后在bin目錄下生成classes.dex文件辩诞。Parallel用于指定將多個(gè)task并行執(zhí)行。

6纺涤、package-res-and-assets

    <target name="package-res-and-assets">
        <exec executable="${aapt}" failonerror="true">
            <arg value="package" />
            <arg value="-f" />
            <arg value="-M" />
            <arg value="AndroidManifest.xml" />
            <arg value="-S" />
            <arg value="${resource-dir}" />
            <arg value="-A" />
            <arg value="${asset-dir}" />
            <arg value="-I" />
            <arg value="${android-jar}" />
            <arg value="-F" />
            <arg value="${resources-package}" />
        </exec>
    </target>

package-res-and-assets中執(zhí)行了aapt命令译暂,來(lái)將res、assets目錄下的資源文件打包到resources.ap_
aapt package -f -M <AndroidManifest.xml路徑> -S <res路徑> -A <assert路徑> -I <android.jar路徑> -F <輸出的包目錄+包名>

7撩炊、package

 <target name="package" depends="dex,package-res-and-assets">
        <exec executable="${apk-builder}" failonerror="true">
            <arg value="${out-unsigned-package-ospath}" />
            <arg value="-u" />
            <arg value="-z" />
            <arg value="${resources-package-ospath}" />
            <arg value="-f" />
            <arg value="${dex-ospath}" />
            <arg value="-rf" />
            <arg value="${srcdir-ospath}" />
            <arg value="-rj" />
            <arg value="${external-libs-ospath}" />
            <arg value="-nf" />
            <arg value="${native-libs-dir-ospath}" />
        </exec>
    </target>

通過(guò)apkbuilder.bat工具根據(jù)classes.dex文件和resources.ap_生成未混淆的apk包
apkbuilder <輸出apk文件路徑> -z <資源文件路徑> -f <dex文件路徑> -rf <源碼目錄> -rj <第三方j(luò)ar包目錄> -nf <本地庫(kù)目錄>

8外永、jarsigner

    <target name="jarsigner" depends="package">
        <exec executable="${jarsigner}" failonerror="true">
            <arg value="-verbose" />
            <arg value="-storepass" />
            <arg value="${password}" />
            <arg value="-keystore" />
            <arg value="${keystore.path}" />
            <arg value="-signedjar" />
            <arg value="${out-signed-package-ospath}" />
            <arg value="${out-unsigned-package-ospath}" />
            <arg value="${keystore.key}" />
        </exec>
    </target>

jarsigner是對(duì)上面生成的apk文件進(jìn)行簽名操作
-verbose 簽名時(shí)輸出詳細(xì)信息
-storepass 密鑰庫(kù)密碼
-keystore 密鑰庫(kù)位置
-signedjar 后面接的參數(shù)依次是 簽名后的apk、待簽名的apk拧咳、密鑰庫(kù)別名

9伯顶、zipalign

    <target name="zipalign" depends="jarsigner">
        <exec executable="${zipalign}" failonerror="true">
            <arg value="-v" />
            <arg value="-f" />
            <arg value="4" />
            <arg value="${out-signed-package-ospath}" />
            <arg value="${zipalign-package-ospath}" />
        </exec>
    </target>

zipalign target通過(guò)zipalign工具對(duì)簽名后的apk包進(jìn)行字節(jié)對(duì)齊,好處是能夠減少應(yīng)用程序的RAM內(nèi)存資源消耗
-v 表示輸出詳細(xì)信息
-f 表示如果輸出文件已存在 則直接覆蓋
4 表示對(duì)齊為4個(gè)字節(jié)

10、release

    <target name="release" depends="zipalign">  
        <!-- 刪除未簽名apk -->  
        <delete file="${out-unsigned-package-ospath}"/>  
        ......  
    </target>

至此打一個(gè)完整的帶簽名的可發(fā)布的包的流程就結(jié)束了祭衩。執(zhí)行ant release命令即可完成打包灶体。

打包成jar

由于jar包中不能包含資源文件,所以要通過(guò)jar包提供UI視圖供第三方使用掐暮,可以通過(guò)如下方式實(shí)現(xiàn):

1蝎抽、使用硬編碼來(lái)實(shí)現(xiàn)布局文件
2、布局中的資源文件需放在assets文件夾中路克,然后打包到j(luò)ar中樟结,通過(guò)流的方式讀取。這種方式將資源文件放在assets目錄下和java代碼一起打包為jar,其他工程依賴該jar包時(shí)衷戈,可以只引用jar包狭吼,不需要再額外導(dǎo)入資源文件,在該工程編譯應(yīng)用時(shí)會(huì)將jar包assets目錄中的文件與該工程中的assets目錄中的文件合并殖妇。注意assets目錄中的文件名與所導(dǎo)入工程中的文件名稱不能重復(fù)刁笙,否則在編譯的時(shí)候會(huì)報(bào)錯(cuò)“Error generating final archive: Found duplicate file for APK”提示有重名文件。
另外谦趣,打包到j(luò)ar中的資源文件必須是編譯之后的資源文件疲吸,即編譯成二進(jìn)制文件,因?yàn)樽x取資源時(shí)是通過(guò)流的方式讀取的前鹅,所以相關(guān)的資源文件必須在編譯成二進(jìn)制文件之后再放入assets打包摘悴。

讀取方式如下

//讀取圖片
InputStream inputStream = context.getAssets().open(path);
Drawable drawable = Drawable.createFromResourceStream(
    context.getResources(), value, inputStream, name);

//讀取xml圖片資源
XmlResourceParser parser = context.getAssets().openXmlResourceParser(path);
Drawable draw = Drawable.createFromXml(context.getResources(), parser);

jar包的構(gòu)建方式與apk的類似,執(zhí)行步驟大概為
aidl->compile->copy_asset->obfuscate->jarsigner
與打包成apk流程相比少了gen-R舰绘、aapt蹂喻、dex、package-res-and-assets捂寿、package口四、zipalign等操作,需要注意就是obfuscate混淆這一步秦陋,

打成jar包時(shí)obfuscate如下:

<!-- Obscure the package file. -->
    <target name="obfuscate" depends="compile, copy-asset">
        <echo>Obscure the class files....</echo>
        <jar basedir="${outdir-classes}" destfile="${out_original_jar}">
        </jar>
        <java jar="${proguard.home}/proguard.jar" fork="true" failonerror="true">
            <arg value="-injars ${out_original_jar}"/>
            <arg value="-injars $other_jar}"/>
            <arg value="-libraryjars ${android-jar}"/>
            ...
            <arg value="-outjars  ${outdir}/${out_obfuscate_jar}"/>
            <arg value="@${proguard.config}"/>
        </java>
    </target>

obfuscate混淆先是執(zhí)行了jar命令蔓彩,將bin目錄下的class文件以及資源文件打包成jar包,然后執(zhí)行proguard命令來(lái)壓縮驳概、優(yōu)化和混淆操作赤嚼。這里需要注意的是如果該工程還依賴了其他jar包(未混淆),則打成jar的同時(shí)需要將其他jar包也引入進(jìn)來(lái)顺又,因?yàn)樽詈髮?duì)外提供的是該工程的jar包更卒。

另外需要注意的是proguard.cfg混淆文件中需要為其他jar包的類文件指明重命名類的包路徑

# Specifies to repackage all class files that are renamed, by moving them into the single given package
-repackageclasses 'com.example.otherjar'

一定要為一些重命名的class文件指明打到j(luò)ar包中的包路徑,jar包中所有的class文件需要有明確的包路徑待榔,以防被第三方apk集成編譯時(shí)逞壁,這些class文件無(wú)法-keep流济,被編譯混淆之后找不到這些類,導(dǎo)致jar包功能異常腌闯。

rename1.png

而增加了路徑指定后绳瘟,重命名的類就會(huì)被打到指定的包路徑下,其他地方對(duì)這些類的調(diào)用也能正常進(jìn)行姿骏。

rename2.png

基本上要介紹的就這么多糖声,可能會(huì)有理解錯(cuò)誤的地方,歡迎一起討論分瘦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蘸泻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嘲玫,更是在濱河造成了極大的恐慌悦施,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件去团,死亡現(xiàn)場(chǎng)離奇詭異抡诞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)土陪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門昼汗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鬼雀,你說(shuō)我怎么就攤上這事顷窒。” “怎么了源哩?”我有些...
    開(kāi)封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵鞋吉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我励烦,道長(zhǎng)坯辩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任崩侠,我火速辦了婚禮,結(jié)果婚禮上坷檩,老公的妹妹穿的比我還像新娘却音。我一直安慰自己,他們只是感情好矢炼,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布系瓢。 她就那樣靜靜地躺著,像睡著了一般句灌。 火紅的嫁衣襯著肌膚如雪夷陋。 梳的紋絲不亂的頭發(fā)上欠拾,一...
    開(kāi)封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音骗绕,去河邊找鬼藐窄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酬土,可吹牛的內(nèi)容都是我干的荆忍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼撤缴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼刹枉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起屈呕,我...
    開(kāi)封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤微宝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后虎眨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蟋软,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年专甩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钟鸵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涤躲,死狀恐怖棺耍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情种樱,我是刑警寧澤蒙袍,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站嫩挤,受9級(jí)特大地震影響害幅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岂昭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一以现、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧约啊,春花似錦邑遏、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至外傅,卻和暖如春纪吮,著一層夾襖步出監(jiān)牢的瞬間俩檬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工碾盟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棚辽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓巷疼,卻偏偏與公主長(zhǎng)得像晚胡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嚼沿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,283評(píng)論 25 707
  • Android插件化基礎(chǔ)的主要內(nèi)容包括 Android插件化基礎(chǔ)1-----加載SD上APKAndroid插件化基...
    隔壁老李頭閱讀 7,121評(píng)論 13 48
  • 最近項(xiàng)目apk方法數(shù)即將達(dá)到65536上限估盘,雖然通過(guò)瘦身減少了一些方法數(shù),但是隨著更多sdk的接入骡尽,終究還是避免不...
    the_q閱讀 16,483評(píng)論 6 39
  • Gradle plugin 3.0 & Android Studio 3.0 我們主要講一下升級(jí)gradle pl...
    coofee閱讀 18,456評(píng)論 6 17
  • 每日晨語(yǔ) 在等待的日子里遣妥,刻苦讀書,謙卑做人攀细,養(yǎng)得深根箫踩,日后才能枝葉茂盛√诽埃——星云大師 家鄉(xiāng)新聞 【1】近日境钟,科技...
    海那邊2016閱讀 233評(píng)論 0 0