自動(dòng)化打包apk總結(jié)并整合資料


打包環(huán)境:

  • 操作系統(tǒng):Centos7.0
  • 編譯腳本:Ant
  • 涉及到的工具:shell命令喷户、aapt隙轻、signapk(簽名)、axmlio(解析庫(kù))瞳购、zipalign、apksigner(簽名)

整理的背影以及說(shuō)初衷

  • 解決當(dāng)前BUG:Android studio 從2.3升級(jí)到3.0后 現(xiàn)自動(dòng)化打包后臺(tái)無(wú)法對(duì)APK進(jìn)行再簽名
  • 很久以前做過(guò)一次Ant的自動(dòng)化亏推,而目前自動(dòng)化打包是接手項(xiàng)目学赛,也恰是使用ant而非gradle年堆,解決BUG同時(shí),借此機(jī)會(huì)做一次總結(jié)
  • 從年初開始盏浇,工作原因更多的接觸Linux变丧,對(duì)shell命令使用增多
  • 開發(fā)了這么多年 但對(duì)打包簽名只停留在模糊的認(rèn)識(shí)

Ready 前置知識(shí)

  • Android 簽名剖析

  • Ant 語(yǔ)法規(guī)則

  • 什么是aapt

  • linux shell簡(jiǎn)單命令



一、Android 簽名剖析

參考資料:http://zzqhost.com/2017/06/17/Android簽名原理剖析/

  • 消息摘要 -Message Digest

    • 簡(jiǎn)稱摘要绢掰,請(qǐng)看英文翻譯痒蓬,是摘要,不是簽名滴劲,網(wǎng)上幾乎所有APK簽名分析的文章都混淆了這兩個(gè)概念攻晒。
    • 消息摘要的特性,很適合來(lái)驗(yàn)證數(shù)據(jù)的完整性班挖,比如在網(wǎng)絡(luò)傳輸過(guò)程中下載一個(gè)大文件BigFile鲁捏,我們會(huì)同時(shí)從網(wǎng)絡(luò)下載BigFile和BigFile.md5,BigFile.md5保存BigFile的摘要萧芙,我們?cè)诒镜厣葿igFile的消息摘要给梅,和BigFile.md5比較,如果內(nèi)容相同双揪,則表示下載過(guò)程正確动羽。
    • 注意,消息摘要只能保證消息的完整性渔期,并不能保證消息的不可篡改性运吓。
  • MD5, SHA-0, SHA-1, SHA-256

    • 這些都是摘要生成算法,和簽名沒有半毛錢關(guān)系擎场。如果非要說(shuō)他們和簽名有關(guān)系羽德,那就是簽名是要借助于摘要技術(shù)。
    • SHA-256是SHA-1的升級(jí)版迅办,現(xiàn)在Android簽名使用的默認(rèn)算法都已經(jīng)升級(jí)到SHA-256了
  • 數(shù)字簽名 - Signature

    • 數(shù)字簽名就是信息的發(fā)送者用自己的私鑰對(duì)消息摘要加密產(chǎn)生一個(gè)字符串宅静,加密算法確保別人無(wú)法偽造生成這段字符串,這段數(shù)字串也是對(duì)信息的發(fā)送者發(fā)送信息真實(shí)性的一個(gè)有效證明站欺。
    • 數(shù)字簽名是 非對(duì)稱密鑰加密技術(shù) + 數(shù)字摘要技術(shù) 的結(jié)合姨夹。
  • 數(shù)字證書 - Certificate

    • 數(shù)字證書是一個(gè)經(jīng) 證書授權(quán)中心 數(shù)字簽名 的包含公開密鑰擁有者信息以及公開密鑰的文件。CERT.RSA包含了一個(gè)數(shù)字簽名以及一個(gè)數(shù)字證書矾策。
  • 簽名三兄弟

    • 從我們解壓出來(lái)的APK目錄里面可以看到有一個(gè)META-INF目錄中
      • MANIFEST.MF:所有文件的摘要信息磷账,但不包括它們仨自己
      • CERT.SF:保存的是MANIFEST.MF的摘要值,以及MANIFEST.MF中每一個(gè)摘要項(xiàng)的摘要值
      • CERT.RSA:保存的是利用密鑰對(duì)CERT.SF進(jìn)行加密生成的數(shù)字簽名和簽名時(shí)用到的數(shù)字證書贾虽,數(shù)字證書保存的就是公鑰和簽名算法
  • 簽名工具

    • jarsigner 在JAVA的bin目錄下
-verbose:簽名命令標(biāo)識(shí)符逃糟。 
-keystore:后面跟著的是你簽名使用的密鑰文件(keystore)的絕對(duì)路徑。 
-storepass:后面跟著的是你密鑰文件(keystore)的密碼 
-signedjar:此后有三個(gè)參數(shù): 
參數(shù)一:簽名后生成的apk文件所要存放的路徑。 
參數(shù)二:未簽名的apk文件的存放路徑绰咽。 
參數(shù)三:你的證書名稱菇肃,通俗點(diǎn)說(shuō)就是你keystore文件的別名,就是在你eclipse進(jìn)行簽名打包時(shí)的Alias的值取募。
例:jarsigner -verbose  -keystore mystore.jks -storepass passwork -signedjar signed.apk unsigned.apk aliasname
  • signapk
例:signapk 簽名文件  密碼   別名  別名密碼  signed.apk unsigned.apk
  • IDE(這就不用說(shuō)了)
  • jarsign和signapk區(qū)別:
    很多文章都說(shuō) 他們的區(qū)別是在于簽名時(shí)使用的文件不一樣琐谤,前者使用的是keystore文件,后者是用pk8,x509.pem文件玩敏,但我在使用當(dāng)中發(fā)現(xiàn) 其實(shí) 都是可以使用keystore的斗忌,原打包ant腳本中就是使用的signapk 如下,很是不解旺聚,但也不重要织阳。

最后經(jīng)驗(yàn)證是因?yàn)閟ignapk對(duì)as3.0打出的包進(jìn)行再簽名時(shí) APK無(wú)法運(yùn)行,改用apksigner翻屈,接下來(lái) 就開始介紹 apksigner卓囚。

      <exec dir="${apk.obj.dir}" executable="${utils.dir}/signapk" >
            <arg value="${keystore.uri}" />
            <arg value="${keystore.password}" />
            <arg value="${keystore.alias}" />
            <arg value="${keystore.alias.password}" />
            <arg value="${apk.obj.dir}/${apkname}-unsigned.apk" />
            <arg value="${apk.obj.dir}/${apkname}-unaligned.apk" />
        </exec>
  • apksigner
    介紹apksigner之前 先說(shuō)一下 什么是V1與V2簽名 這很關(guān)鍵精算。
    從Android 7.0開始, 谷歌增加新簽名方案 V2 Scheme (APK Signature);
    但Android 7.0以下版本, 只能用舊簽名方案 V1 scheme (JAR signing)

V1與V2的區(qū)別:
V1簽名:
來(lái)自JDK(jarsigner), 對(duì)zip壓縮包的每個(gè)文件進(jìn)行驗(yàn)證, 簽名后還能對(duì)壓縮包修改(移動(dòng)/重新壓縮文件)
對(duì)V1簽名的apk/jar解壓,在META-INF存放簽名文件(MANIFEST.MF, CERT.SF, CERT.RSA),
其中MANIFEST.MF文件保存所有文件的SHA1指紋(除了META-INF文件), 由此可知: V1簽名是對(duì)壓縮包中單個(gè)文件簽名驗(yàn)證

V2簽名:
來(lái)自Google(apksigner), 對(duì)zip壓縮包的整個(gè)文件驗(yàn)證, 簽名后不能修改壓縮包(包括zipalign),
對(duì)V2簽名的apk解壓,沒有發(fā)現(xiàn)簽名文件,重新壓縮后V2簽名就失效, 由此可知: V2簽名是對(duì)整個(gè)APK簽名驗(yàn)證

V2簽名優(yōu)點(diǎn)很明顯:
    簽名更安全(不能修改壓縮包)
    簽名驗(yàn)證時(shí)間更短(不需要解壓驗(yàn)證),因而安裝速度加快

注意: apksigner工具默認(rèn)同時(shí)使用V1和V2簽名,以兼容Android 7.0以下版本

由此可見 我們需要使用打包后臺(tái)再打包 是一定不能使用V2簽名的,關(guān)于這個(gè)官方也必未強(qiáng)制要求使用V2 給出了一定的配置方法 :

  • 在IDE中可以進(jìn)行選擇


    image.png
  • 在gradel中可以配置:

signingConfigs {  
    debug {  
        v1SigningEnabled true  
        v2SigningEnabled true  
    }  
    release {  
        v1SigningEnabled true  
        v2SigningEnabled true  
    }  
}  
  • 在使用apksigner時(shí)也給出了參數(shù)設(shè)置
--v1-signing-enabled <true | false>
--v2-signing-enabled <true | false>

說(shuō)完了V1與V2 我們回頭來(lái)看apksigner的使用,
工具目錄在SDK\build-tools\版本號(hào)\lib下埋酬,執(zhí)行

java -jar apksigner.jar sign

參數(shù)說(shuō)明:

  • –ks 你的jks路徑 //jks簽名證書路徑
  • –ks-key-alias 你的alias //生成jks時(shí)指定的alias
  • –ks-pass pass:你的密碼 //KeyStore密碼
  • –key-pass pass:你的密碼 //簽署者的密碼扯键,即生成jks時(shí)指定alias對(duì)應(yīng)的密碼
  • –out output.apk //輸出路徑
  • input.apk //被簽名的apk

示例:

java -jar apksigner.jar sign  --ks key.jks  --ks-key-alias releasekey  --ks-pass pass:pp123456  --key-pass pass:pp123456  --out output.apk   input.apk

段落總結(jié):以上是關(guān)于簽名的資料整合撩满,也是自動(dòng)化打包的核心葵第,當(dāng)前自動(dòng)化打包工具無(wú)法對(duì)AS3.0再打包的關(guān)鍵也在于此,關(guān)鍵就在于signapk過(guò)時(shí)了嘴秸,而AS3.0的升級(jí)又改變很大毁欣,想要自動(dòng)化,就需要將signapk也升級(jí)岳掐,他的取代方案就是使用apksigner凭疮。當(dāng)中我也懷疑過(guò)是不是V2導(dǎo)致的問題,后經(jīng)驗(yàn)證串述,與它無(wú)關(guān)执解,使用AS3.0強(qiáng)制使用V1打包 也一樣不可用,或許打包通過(guò)纲酗,但在安裝時(shí)報(bào)如下錯(cuò)誤:

Failure [INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: Failed reading AndroidManifest.xml in android.util.jar.StrictJarFile@6fa28f: META-INF/MANIFEST.MF has invalid digest for AndroidManifest.xml in AndroidManifest.xml]

說(shuō)到這里思路就清晰了衰腌,接下來(lái)的工作就是將signapk替換為apksigner,并結(jié)合使用在ANT當(dāng)中觅赊。



二右蕊、Ant 語(yǔ)法規(guī)則:

此項(xiàng)目從2015年以來(lái) 一直使用Ant,之前也有做過(guò),而這次問題的主因并不在ant是否過(guò)時(shí)吮螺,as3.0是否一定要用最新的gradle的問題饶囚,所以繼續(xù)在ANT基礎(chǔ)上修改帕翻,以前并未做過(guò)總結(jié),就又到處查了一遍資料坯约,太麻煩熊咽,所以就著這次機(jī)會(huì)做個(gè)最終了結(jié)莫鸭。

參考資料:
https://blog.csdn.net/leeandmins/article/details/50481450
https://blog.csdn.net/megatronkings/article/details/48012125
http://tianlihu.iteye.com/blog/741239

從結(jié)果可以看出 他需要用到build.xml堕花,通俗的講 build.xml就ant的核心代碼文件,build.xml是默認(rèn)的ant執(zhí)行文件

ant 
在當(dāng)前目錄下的build.xml運(yùn)行Ant粥鞋,執(zhí)行缺省的target缘挽。

ant -buildfile build-test.xml 
在當(dāng)前目錄下的build-test.xml運(yùn)行Ant,執(zhí)行缺省的target呻粹。

ant -buildfile build-test.xml clean 
在當(dāng)前目錄下的build-test.xml運(yùn)行Ant壕曼,執(zhí)行一個(gè)叫做clean的target。

ant -buildfile build-test.xml -Dbuild=build/classes clean 
在當(dāng)前目錄下的build-test.xml運(yùn)行Ant等浊,執(zhí)行一個(gè)叫做clean的target腮郊,并設(shè)定build屬性的值為build/classes。 
  • build.xml文件的基本結(jié)構(gòu)
<?xml version="1.0" encoding="UTF-8"?>  
<project name="test" default="build">  
      <property name="file.dir" value="D://"/>  
        <property file="local.properties" />  
        <loadproperties srcFile="project.properties" />  
        <import file="rules.xml" optional="true" />  
        <target name="build">  
             <echo>runing...</echo>  
        </target>  
       <target name="debug" depends="build">  
             <echo level="info">${file.dir} debugging...</echo>  
       </target>  
</project>

project 根標(biāo)簽筹燕。name屬性表示項(xiàng)目名稱轧飞,沒什么作用;default屬性表示默認(rèn)執(zhí)行命令撒踪,cmd命令行中使用ant和ant default屬性值(本例是ant build) 兩種方式等效过咬。

property 定義類標(biāo)簽。可以定義一些常量值制妄,需要注意:定義后理論不能再修改(其實(shí)可以通過(guò)第三方庫(kù)修改)掸绞。比如第3行定義了一個(gè)file.dir的變量,值為”D://“忍捡,引用時(shí)使用 ${file.dir}調(diào)用集漾。第4行,是引入一個(gè)properties文件(里面定義了很多property)砸脊,相當(dāng)于導(dǎo)包具篇。

loadproperties 引用標(biāo)簽。功能和第4行<property file=""/>等同凌埂,表示引入一個(gè)properties定義集群驱显。好處是便于封裝和管理。

import 引入標(biāo)簽。和loadproperties不同的是埃疫,import是引入另一個(gè)構(gòu)建文件伏恐,包括變量和執(zhí)行命令。

target 執(zhí)行標(biāo)簽栓霜。可以在cmd命令行中直接ant + target執(zhí)行翠桦,比如以上腳本可以執(zhí)行: ant build 和 ant debug。target標(biāo)簽中有個(gè)depends屬性胳蛮,表示執(zhí)行命令依賴销凑。如果要執(zhí)行debug命令,會(huì)自動(dòng)先執(zhí)行depends里面的命令仅炊。以上腳本執(zhí)行 ant debug斗幼,實(shí)際是執(zhí)行了 ant build 和 ant debug

echo 日志標(biāo)簽。表示日志輸出抚垄,能在cmd命令中打印顯示蜕窿,level屬性表示:日志級(jí)別。 比較特殊的是echo中可以引用變量呆馁,用法同變量調(diào)用方式${name}桐经。

  • ant的常用語(yǔ)法

1、文件語(yǔ)句

    文件操作是ant中最常用的基本操作智哀,包括創(chuàng)建次询、復(fù)制、刪除瓷叫、遍歷等屯吊。由于ant涉及最多的就是文件操作,所以它的api相對(duì)來(lái)說(shuō)非常豐富摹菠,讓我們來(lái)逐一介紹和學(xué)習(xí)盒卸。

    創(chuàng)建:mkdir標(biāo)簽。 傳入一個(gè)文件路徑次氨,直接創(chuàng)建出一個(gè)文件目錄蔽介。然而不知為何ant沒有提供創(chuàng)建文件的功能。
<mkdir dir="D:/test"/>
    刪除:delete標(biāo)簽煮寡。刪除文件或文件夾
<delete file="D:/test/example.txt"/>  
<delete dir="D:/test"/>  
  移動(dòng):move標(biāo)簽虹蓄。包括文件重命名、文件移動(dòng)幸撕、文件目錄移動(dòng)薇组。
<!-- 重命名 -->  
<move file="D:/test/example1.txt" tofile="D:/test/example2.txt"/>  
<!-- 移動(dòng)文件至新目錄,新目錄會(huì)自動(dòng)創(chuàng)建 -->  
<move file="D:/test/example2.txt" todir="D:/test2"/>  
<!-- 文件夾移動(dòng) -->  
<move dir="D:/test/example2.txt" todir="D:/test2"/>  
  復(fù)制:copy標(biāo)簽坐儿。文件復(fù)制律胀。
<!-- 文件復(fù)制宋光,指定新文件名 -->  
<copy file="D:/test/example.txt" tofile="D:/test/example2.txt"/>  
<!-- 文件復(fù)制,指定新文件目錄 -->  
<copy file="D:/test/example.txt" todir="D:/test/new/"/>  
<!-- 文件夾復(fù)制炭菌,指定新文件夾 -->  
<copy dir="D:/test/" todir="D:/test/new/"/>  

2罪佳、條件語(yǔ)句

         condition標(biāo)簽,配合istrue或者isfalse使用黑低。
<condition property="check">  
    <istrue value="false" />  
</condition>  
<target name="build" if="check">  
    <echo>build running...</echo>  
</target>  

在執(zhí)行名為build的target任務(wù)時(shí)赘艳,由于target中含有if的標(biāo)簽,所以需要判斷名為check的條件語(yǔ)句的值投储,但是istrue=false的語(yǔ)句表示條件不符合第练,echo并不會(huì)執(zhí)行。如果改成istrue=true玛荞,echo將執(zhí)行。當(dāng)然以上語(yǔ)句等價(jià)于:

<condition property="check">  
    <isfalse value="true" />  
</condition>  
<target name="build" if="check">  
    <echo>build running...</echo>  
</target>  

需要注意下呕寝,istrue和isfalse兩種標(biāo)簽不能同時(shí)存在勋眯。
除了直接使用istrue指定條件語(yǔ)句的值,還能動(dòng)態(tài)地使用equals比較變量下梢,比如:

<property name="id" value="99"></property>  
    <condition property="check">  
        <equals arg1="${id}" arg2="100"/>  
    </condition>  
    <target name="build" if="check">  
        <echo>build running...</echo>  
    </target>  

3客蹋、循環(huán)語(yǔ)句
ant本身并沒有提供循環(huán)語(yǔ)句,但是我們可以借助于ant-contrib.jar使用循環(huán)語(yǔ)句孽江,舉個(gè)簡(jiǎn)單的例子:

<property name="ant-contrib" value="E:\\Android\\android-sdk\\tools\\lib\\ant-contrib-1.0b3.jar"></property>  
   <taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" classpath="${ant-contrib}"/>  
<target name="build">  
    <foreach list="1,2,3,4,5,6,7,8,9" param="number" delimiter="," target="log"/>    
</target>  
<target name="log">  
    <echo>foreach running: ${number}</echo>  
</target>  

4讶坯、自定義語(yǔ)句

    ant的魅力所在之處就是強(qiáng)大的自定義語(yǔ)句,比如上面的foreach語(yǔ)句岗屏。ant官方庫(kù)只定義了一些簡(jiǎn)單的語(yǔ)句辆琅,但是在實(shí)際項(xiàng)目中遠(yuǎn)遠(yuǎn)不足以滿足我們的需要,比如新建一個(gè)文件这刷。這里我們就用自定義語(yǔ)句來(lái)實(shí)現(xiàn)下婉烟。

    ant的原理是每個(gè)語(yǔ)句標(biāo)簽映射一個(gè)java類文件,每個(gè)標(biāo)簽里的屬性則映射java類的變量暇屋,有點(diǎn)類似spring中xml映射javabean似袁。每個(gè)ant標(biāo)簽映射的java類文件不是隨意編寫的,有一定的規(guī)范咐刨。

    在ant安裝目錄下的lib文件目錄中有個(gè)名為ant.jar的包昙衅,這個(gè)就是ant的規(guī)范標(biāo)準(zhǔn)庫(kù),自定義語(yǔ)句Java類都需要依賴它來(lái)編譯定鸟,同時(shí)每個(gè)語(yǔ)句必須繼承其中名為Task.java的基類而涉,復(fù)寫execute方法執(zhí)行自定義操作。
package com.ant.test;  
  
import java.io.File;  
import java.io.IOException;  
  
import org.apache.tools.ant.BuildException;  
import org.apache.tools.ant.Task;  
  
public class FileCreater extends Task{  
  
    private String fileName;  
      
    public void setName(String fileName){  
        this.fileName = fileName;  
    }  
      
    @Override  
    public void execute() throws BuildException {  
        try {  
            new File(fileName).createNewFile();  
        } catch (IOException e) {  
            log("create file '" + fileName + "' failed!");  
        }  
        log("create file '" + fileName + "' successful!");  
        super.execute();  
    }  
}  

上面定義了創(chuàng)建文件的自定位標(biāo)簽仔粥,把這個(gè)java文件打成jar包婴谱,然后就可以在build.xml使用了蟹但,xml內(nèi)容如下:

<property name="fileJar" value="D:/file.jar"></property>  
   <taskdef name="filecreater" classname="com.ant.test.FileCreater" classpath="${fileJar}"/>  
<target name="build">  
    <filecreater name="D:/test.txt"/>    
</target> 

以上執(zhí)行的操作是創(chuàng)建一個(gè)路徑為D:/test.txt的文件。filecreater是映射FileCreater.java的自定義標(biāo)簽谭羔,name屬性傳入文件路徑名华糖,會(huì)自動(dòng) 反射調(diào)用FileCreater.java中的setName方法注入?yún)?shù)值。在FileCreater.java中有個(gè)log打印輸出方法瘟裸,可以在cmd中輸出客叉,極大方便我們的調(diào)試。

最后 如下代碼是替換signapk為apksigner的主要代碼

     <!--   <exec dir="${apk.obj.dir}" executable="${utils.dir}/signapk" >
            <arg value="${keystore.uri}" />
            <arg value="${keystore.password}" />
            <arg value="${keystore.alias}" />
            <arg value="${keystore.alias.password}" />
            <arg value="${apk.obj.dir}/${apkname}-unsigned.apk" />
            <arg value="${apk.obj.dir}/${apkname}-unaligned.apk" />
        </exec>   -->

        <exec executable="java">
            <arg line="-jar ${utils.dir}/lib/apksigner.jar sign --ks ${keystore.uri} --ks-key-alias ${keystore.alias} --ks-pass pass:${keystore.password} --key-pass pass:${keystore.password} --v2-signing-enabled false --out ${apk.obj.dir}/${apkname}-unaligned.apk ${apk.obj.dir}/${apkname}-unsigned.apk"/>
        </exec>

總結(jié) 以上兩部分是這次任務(wù)的主要內(nèi)容话告,除了涉及這兩塊知識(shí)外 再就有些零散的appt知識(shí)點(diǎn)和linux shell命令兼搏,我做一下簡(jiǎn)單整理



三、什么是aapt

參考資料:
https://blog.csdn.net/electricity/article/details/6540247

項(xiàng)目用到的不多沙郭,而這塊的知識(shí)點(diǎn)內(nèi)容比較多 限于篇幅過(guò)長(zhǎng) 在此就簡(jiǎn)單列出 此次用到的一些點(diǎn)

打包好的apk中移除文件
aapt r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]

添加文件到打包好的apk中
 aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]

實(shí)例:
<target name="build-apk">
        <sequential>
            <copy file="${apk.obj.dir}/${apkfile}" tofile="${apk.obj.dir}/${apkname}-unsigned.apk" overwrite="true" />
            <echo level="info">remove AndroidManifest</echo>
            <exec dir="${apk.obj.dir}" executable="${utils.dir}/aapt">
                <arg value="r" />
                <arg value="${apk.obj.dir}/${apkname}-unsigned.apk" />
                <arg value="AndroidManifest.xml" />
            </exec> 

            <exec dir="${apk.obj.dir}" executable="${utils.dir}/aapt">
                <arg value="a" />
                <arg value="${apk.obj.dir}/${apkname}-unsigned.apk" />
                <arg value="AndroidManifest.xml" />
            </exec>
        </sequential>
    </target>


四佛呻、linux shell簡(jiǎn)單命令

參考資料:https://www.cnblogs.com/yinheyi/p/6648242.html

LOCAL_PATH=`dirname $0`
cd $LOCAL_PATH

if [ "$1" == "" ]; then
    utils/ant/bin/ant help
else
    echo $@
    utils/ant/bin/ant $@
fi

總結(jié)完回頭一看 篇幅真的挺長(zhǎng),呵呵呵 沒辦法 項(xiàng)目總結(jié) 內(nèi)容是多一點(diǎn)病线,對(duì)于markdown的排版也不是很熟練吓著,整篇來(lái)看可能有些臃腫,結(jié)構(gòu)不清后繼再優(yōu)化吧送挑,熟能生巧绑莺,寫文章總結(jié)雖說(shuō)也是門技術(shù)活,但也是熟練工種惕耕,總結(jié)是越發(fā)的重要纺裁,會(huì)越來(lái)越好的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末司澎,一起剝皮案震驚了整個(gè)濱河市欺缘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惭缰,老刑警劉巖浪南,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漱受,居然都是意外死亡络凿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門昂羡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)絮记,“玉大人,你說(shuō)我怎么就攤上這事虐先≡狗撸” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蛹批,是天一觀的道長(zhǎng)撰洗。 經(jīng)常有香客問我篮愉,道長(zhǎng),這世上最難降的妖魔是什么差导? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任试躏,我火速辦了婚禮,結(jié)果婚禮上设褐,老公的妹妹穿的比我還像新娘颠蕴。我一直安慰自己,他們只是感情好助析,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布犀被。 她就那樣靜靜地躺著,像睡著了一般外冀。 火紅的嫁衣襯著肌膚如雪寡键。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天锥惋,我揣著相機(jī)與錄音昌腰,去河邊找鬼。 笑死膀跌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的固灵。 我是一名探鬼主播捅伤,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巫玻!你這毒婦竟也來(lái)了丛忆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仍秤,失蹤者是張志新(化名)和其女友劉穎熄诡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诗力,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凰浮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苇本。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袜茧。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瓣窄,靈堂內(nèi)的尸體忽然破棺而出笛厦,到底是詐尸還是另有隱情,我是刑警寧澤俺夕,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布裳凸,位于F島的核電站贱鄙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏姨谷。R本人自食惡果不足惜逗宁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望菠秒。 院中可真熱鬧疙剑,春花似錦、人聲如沸践叠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)禁灼。三九已至管挟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弄捕,已是汗流浹背僻孝。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留守谓,地道東北人穿铆。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像斋荞,于是被迫代替她去往敵國(guó)和親荞雏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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

  • 關(guān)于作者: 李濤平酿,騰訊Android工程師凤优,14年加入騰訊SNG增值產(chǎn)品部,期間主要負(fù)責(zé)手Q動(dòng)漫蜈彼、企鵝電競(jìng)等項(xiàng)目的...
    稻草人_3e17閱讀 3,595評(píng)論 0 10
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,528評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理筑辨,服務(wù)發(fā)現(xiàn),斷路器幸逆,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • 一、前言 Hi蚕甥,大家好哪替,我是承香墨影! 當(dāng)我們需要發(fā)布一款 App 到應(yīng)用市場(chǎng)的時(shí)候菇怀,一般需要我們針對(duì)不同的市場(chǎng)生...
    承香墨影閱讀 1,095評(píng)論 0 13
  • 鬧市中凭舶,隱著一個(gè)人的誕生地 賺著 千萬(wàn)只舉過(guò)頭頂?shù)氖?和磨破膝蓋的棉與綢 十萬(wàn)片葉子上十萬(wàn)獅子怒吼 金瓦殿晌块,菩提樹...
    向上的植物閱讀 343評(píng)論 0 3