安卓系统的资源编译_第1页
安卓系统的资源编译_第2页
安卓系统的资源编译_第3页
安卓系统的资源编译_第4页
安卓系统的资源编译_第5页
已阅读5页,还剩175页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、安卓的资源编译过程一APK的结构以及生成APK是Android Package的缩写,即Android application package文件或Android安装包。每个要安装到Android平台的应用都要被编译打包为一个单独的文件,扩展名为 .apk。APK文件是用编译器编译生成的文件包,其中包含了应用的二进制代码、资源、配置文件等。通过将APK文件直接传到Android手机中执行即可安装。APK文件其实就是zip格式,但其扩展名被改为apk。在这里我们为了详细讲述Android应用程序我们将创建一个永恒的话题, 它就是HelloWorl

2、d程序,在这里我们创建的Android的HelloWorld程序的目录结构如下所示:一个典型的APK文件通常由下列内容组成:   AndroidManifest.xml       程序全局配置文件   classes.dex                Dalvik字节码   

3、;resources.arsc             资源索引表, 解压缩resources.ap_就能看到   res                      该目录存放资源文件(图片,文本,xml布局)

4、   assets                    该目录可以存放一些配置文件   src                    &#

5、160;  java源码文件   libs                     存放应用程序所依赖的库   gen                

6、     编译器根据资源文件生成的java文件   bin                      由编译器生成的apk文件和各种依赖的资源   META-INF         

7、;       该目录下存放的是签名信息首先来看一下使用Java语言编写的Android应用程序从源码到安装包的整个过程,示意图如下,其中包含编译、链接和签名等:(1). 使用aapt工具将资源文件生成R.java文件, resources.arsc和打包资源文件(2). 使用aidl工具将.aidl文件编译成.java文件(3). 使用javac工具将.java文件编译成.class文件(4). 使用dx脚本将众多.class文件转换成一个.dex文件(5). 使

8、用apkbuilder脚本将资源文件和.dex文件生成未签名的apk安装文件(6). 使用jdk中的jarsigner对apk安装文件进行签名上述工具都保存在android-sdk-linux中的tools/和platform-tools文件夹下面.范例:src/com.example.helloworldactivity:package com.example.helloworldactivity;import android.app.Activity;import android.os.Bundle;import android.view.

9、View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity     private final static String TAG = "MainActivity"

10、;    private TextView mTextView = null;    Override    protected void onCreate(Bundle savedInstanceState)         super.onCreate(savedInstanceState);  

11、;      setContentView(R.layout.activity_main);        mTextView = (TextView)findViewById(R.id.text_view);        Button showButton = (Button)findViewById(R.id.button

12、);        showButton.setOnClickListener(new OnClickListener()             public void onClick(View v)            &#

13、160;    mTextView.setText(R.string.hello_world);                    );    res/layout/activity_main.xml:<LinearLayout xmlns:android="  

14、60; xmlns:tools="    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <Button    &#

15、160;   android:id="+id/button"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:te

16、xt="string/show" />    <TextView        android:id="+id/text_view"        android:layout_width="match_parent"        an

17、droid:layout_height="wrap_content"        android:text="" /></LinearLayout>res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?><resources>    <string

18、60;name="app_name">HelloWorldActivity</string>    <string name="action_settings">Settings</string>    <string name="show">Show</string>    <string name="h

19、ello_world">Hello world!</string></resources>AndroidManifest.xml:<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="    package="com.example.helloworldactivity"    

20、android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="

21、17" />    <application        android:allowBackup="true"        android:icon="drawable/ic_launcher"        android:label=&qu

22、ot;string/app_name"        android:theme="style/AppTheme" >        <activity            android:name="com.example.helloworldactiv

23、ity.MainActivity"            android:label="string/app_name" >            <intent-filter>          &#

24、160;     <action android:name="ent.action.MAIN" />                <category android:name="ent.category.LAUNCHER" /> 

25、           </intent-filter>        </activity>    </application></manifest>我们前面创建的HelloWorldActivity应用程序资源目录结构如下所示:project    接下来,我们在HelloWor

26、ldActivity工程目录下可以使用aapt命令:aapt p -f -m -J mygen/  -S res/ -I /tool/android-sdk-linux/platforms/android-17/android.jar -A assets/ -M AndroidManifest.xml -F helloworldresources.apk在mygen目录下生成一个资源ID文件R.java和在当前目录下生成一个名为hell

27、oworldresources.apk的资源包,解压缩里面内容如下所示:  被打包的APK资源文件中包含有:资源索引表文件resources.arsc, AndroidManifest.xml二进制文件和res目录下的应用程序图片资源及layout目录下的二进制activity_main.xml文件, res目录下信息如下所示:  注意:res/values目录下的字符串信息被编译进了resources.arsc资源索引文件中,而在R.java文件中仅仅保存了资源ID信息. R.java信息如下所示:package 

28、;com.example.helloworldactivity;public final class R     public static final class attr         public static final class dimen        

29、 public static final int activity_horizontal_margin=0x7f040000;        public static final int activity_vertical_margin=0x7f040001;        public static final c

30、lass drawable         public static final int ic_launcher=0x7f020000;        public static final class id         public 

31、;static final int button=0x7f070000;        public static final int text_view=0x7f070001;        public static final class layout      

32、   public static final int activity_main=0x7f030000;        public static final class string         public static final int action_settings

33、=0x7f050001;        public static final int app_name=0x7f050000;        public static final int hello_world=0x7f050003;        public s

34、tatic final int show=0x7f050002;        public static final class style                 public static final int AppBaseT

35、heme=0x7f060000;                public static final int AppTheme=0x7f060001;    下面我们根据分析appt的源码详细讲述命令:aapt p -f -m -J mygen/  -S res/ -

36、I /tool/android-sdk-linux/platforms/android-17/android.jar -A assets/ -M AndroidManifest.xml -F helloworldresources.apk是如何将上述应用程序资源编译生成一个R.java文件, 资源索引表文件resources.arsc, AndroidManifest.xml二进制文件和res目录下的应用程序图片资源及layout目录下的二进制activity_main.xml文件的.appt入口函数ma

37、in具体实现如下所示:路径:frameworks/base/tools/aapt/Main.cppint main(int argc, char* const argv)    char *prog = argv0;    Bundle bundle;    / 定义一个Bundle类存储appt命令的各种编译选项    bool

38、0;wantUsage = false;    int result = 1;    / pessimistically assume an error.    int tolerance = 0;/* default to compression * 设置默认的压缩标准*/   

39、; bundle.setCompressionMethod(ZipEntry:kCompressDeflated);    if (argc < 2)         wantUsage = true;        goto bail;      &#

40、160; if (argv10 = 'v')        bundle.setCommand(kCommandVersion);    .    else if (argv10 = 'p')  / 命令行选项p表示我们要打包资源     

41、0;  bundle.setCommand(kCommandPackage);.    argc -= 2;    argv += 2;    /*     * Pull out flags.  We support "-fv" and "-f

42、60;-v".     * 一下while循环将各种aapt编译选项提取出来存放到bundle中 */    while (argc && argv00 = '-')         /* flag(s) found */    

43、0;   const char* cp = argv0 +1;        while (*cp != '0')             switch (*cp)       

44、60;     .            case 'f':  / 如果编译出来的文件已经存在,强制覆盖                bundle.setForce(true);  /

45、0;bundle.mForce(bool)                break;            .            case 'm': 

46、0;/ 使生成的包的目录存放在-J参数指定的目录                bundle.setMakePackageDirs(true); / bundle.mMakePackageDirs(bool)                break

47、;            .            case 'A': / assert文件夹路径                argc-; 

48、               argv+;                if (!argc)               

49、60;     fprintf(stderr, "ERROR: No argument supplied for '-A' optionn");                    wantUsage = true;

50、60;                   goto bail;                            

51、    convertPath(argv0); / 装换为指定OS的路径                bundle.setAssetSourceDir(argv0); / mAssetSourceDir(const char*)          

52、      break;            .            case 'I':  / 某个版本平台的android.jar的路径        

53、60;       argc-;                argv+;                if (!argc)      

54、               fprintf(stderr, "ERROR: No argument supplied for '-I' optionn");               

55、60;    wantUsage = true;                    goto bail;                  

56、60;             convertPath(argv0);/ mPackageIncludes.add(file);   android:Vector<const char*>                bundle.addPack

57、ageInclude(argv0);                break;            case 'F':  / 具体指定APK文件的输出         &

58、#160;      argc-;                argv+;                if (!argc)      

59、0;              fprintf(stderr, "ERROR: No argument supplied for '-F' optionn");                &

60、#160;   wantUsage = true;                    goto bail;                   &

61、#160;            convertPath(argv0);/ mOutputAPKFile(const char*)                bundle.setOutputAPKFile(argv0);      &#

62、160;         break;            case 'J':  /  指定生成的R.java 的输出目录                

63、; argc-;                argv+;                if (!argc)            &#

64、160;        fprintf(stderr, "ERROR: No argument supplied for '-J' optionn");                    wantUsage&#

65、160;= true;                    goto bail;                         

66、;       convertPath(argv0);                bundle.setRClassDir(argv0); / mRClassDir(const char*)            &#

67、160;   break;            case 'M':  / 指定AndroidManifest.xml文件路径                argc-;     &#

68、160;          argv+;                if (!argc)                    

69、; fprintf(stderr, "ERROR: No argument supplied for '-M' optionn");                    wantUsage = true;     

70、;               goto bail;                                co

71、nvertPath(argv0);/ mAndroidMainifestFile(const char*)                bundle.setAndroidManifestFile(argv0);                 br

72、eak;            .            case 'S':  / res文件夹路径                argc-;

73、                argv+;                if (!argc)              

74、60;      fprintf(stderr, "ERROR: No argument supplied for '-S' optionn");                    wantUsage = tr

75、ue;                    goto bail;                           

76、     convertPath(argv0);/ android:Vector<const char*> mResourceSourceDirs;/ mResourceSourceDirs.insertAt(dir,0);                bundle.addResourceSourceDir(argv0); 

77、               break;            .            default:        

78、60;       fprintf(stderr, "ERROR: Unknown flag '-%c'n", *cp);                wantUsage = true;      &#

79、160;         goto bail;                        cp+;             &

80、#160;  argc-;        argv+;        /*     * We're past the flags.  The rest all goes straight in.     

81、;* 设置Bundle的成员变量mArgv和mArgc分别为argv, argc */    bundle.setFileSpec(argv, argc);    /* 通过handleCommand函数来处理指定命令 */    result = handleCommand(&bundle);bail:    if (wantUsage)

82、         usage();        result = 2;        /printf("-> returning %dn", result);    return result;处理完aapt的编译选项之后

83、,接着调用handleCommand函数来处理对应的功能:路径:frameworks/base/tools/aapt/Main.cppint handleCommand(Bundle* bundle).    switch (bundle->getCommand() .    case kCommandPackage:   return doPackage(bundle);.    

84、;default:        fprintf(stderr, "%s: requested command not yet supportedn", gProgName);        return 1;    最终打包APK的工作由函数doPackage完成,而打包一个应用程序资源的过程非常

85、复杂,我们分如下模块一一讲解:一. 收录一个应用程序所有资源文件路径:frameworks/base/tools/aapt/Command.cpp/* * Package up an asset directory and associated application files. * 打包应用程序中的资源文件 */int doPackage(Bundle* bundle)    const

86、60;char* outputAPKFile;    int retVal = 1;    status_t err;    sp<AaptAssets> assets;    int N;    FILE* fp;    String8 dependenc

87、yFile;./ 检查aapt打包时的参数是否都存在    N = bundle->getFileSpecCount();if (N < 1 && bundle->getResourceSourceDirs().size() = 0   && bundle->getJarFiles().size() = 0   

88、   && bundle->getAndroidManifestFile() = NULL   && bundle->getAssetSourceDir() = NULL)         fprintf(stderr, "ERROR: no input filesn"); 

89、       goto bail;        / 得到最终将资源打包输出到的APK名称outputAPKFile = bundle->getOutputAPKFile();/ Make sure the filenames provided exist and are of the app

90、ropriate type./ 检查该文件是否存在不存在则创建,并确定其实常规文件    if (outputAPKFile)         FileType type;        type = getFileType(outputAPKFile);      &

91、#160; if (type != kFileTypeNonexistent && type != kFileTypeRegular)             fprintf(stderr,               &#

92、160;"ERROR: output file '%s' exists but is not regular filen",                outputAPKFile);          

93、0; goto bail;            / Load the assets./ 创建一个AaptAssets对象    assets = new AaptAssets();    ./* 1.调用AaptAssets类的成员函数slurpFromArgs将AndroidManifest.x

94、ml文件,* 目录assets和res下的资源目录和资源文件收录起来保存到AaptAssets中的* 成员变量中 */    err = assets->slurpFromArgs(bundle);    if (err < 0)         goto bail;     

95、   .AaptAssets的slurpFromArgs函数的具体实现如下所示:路径:frameworks/base/tools/aapt/AaptAssets.cppssize_t AaptAssets:slurpFromArgs(Bundle* bundle)    int count;    int totalCount = 0;FileType type;/ 获取res目录的路径 

96、0;  const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();    const size_t dirCount =resDirs.size();    sp<AaptAssets> current = this;/ 获取bundle内所保存的a

97、apt的命令选项个数,即要完成的功能个数    const int N = bundle->getFileSpecCount();    /*     * If a package manifest was specified, include that first.     *&#

98、160;如果bundle中指定了AndroidManifest.xml文件,则首先包含它 */    if (bundle->getAndroidManifestFile() != NULL)         / place at root of zip.        String8

99、0;srcFile(bundle->getAndroidManifestFile();/* 每向AaptAssets的对象中添加一个资源文件或者一个资源目录都要新建一个* 类型AaptGroupEntry的空对象并将其添加到一个类型为SortedVector的* AaptAssets的成员变量mGroupEntries中, 在这里调用addFile函数是* 将AndroidManifest.xml文件添加到成员变量mFiles中去.*/        addF

100、ile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),                NULL, String8();/* 每添加一个资源就加1统计一次 */        totalCount+;   

101、;     /*     * If a directory of custom assets was supplied, slurp 'em up.     * 判断是否指定了assets文件夹,如果指定则解析它 */    if (bundle->get

102、AssetSourceDir()         const char* assetDir = bundle->getAssetSourceDir();  / 获取目录名称        FileType type = getFileType(assetDir); / 获取目录类型  

103、;      if (type = kFileTypeNonexistent)             fprintf(stderr, "ERROR: asset directory '%s' does not existn", assetDir); &

104、#160;          return UNKNOWN_ERROR;                if (type != kFileTypeDirectory)           &

105、#160; fprintf(stderr, "ERROR: '%s' is not a directoryn", assetDir);            return UNKNOWN_ERROR;             

106、;   String8 assetRoot(assetDir);/* 创建一个名为”assets”的AaptDir对象 */        sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir);        AaptGroupEntry group;/* 调用A

107、aptDir的成员函数slurpFullTree收录目录“assets”下的资源文件,* 并返回资源文件个数 */        count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,                 

108、;                           String8(), mFullAssetPaths);        if (count < 0)    

109、         totalCount = count;            goto bail;                if (count > 0)&#

110、160;            mGroupEntries.add(group);        /* 统计资源文件总个数 */        totalCount += count;        

111、if (bundle->getVerbose()            printf("Found %d custom asset file%s in %sn",                  

112、60;count, (count=1) ? "" : "s", assetDir);        /*     * If a directory of resource-specific assets was supplied, slurp 'em 

113、up.     * 收录指定的res资源目录下的资源文件 */    for (size_t i=0; i<dirCount; i+)         const char *res = resDirsi;        if

114、0;(res)             type = getFileType(res);  / 获取文件类型            if (type = kFileTypeNonexistent)      &

115、#160;          fprintf(stderr, "ERROR: resource directory '%s' does not existn", res);                return

116、0;UNKNOWN_ERROR;                        if (type = kFileTypeDirectory) / 如果指定了多个res资源目录文件, 则为其创建多个AaptAssets/ 类来分别收录这些目录中的信息,并将其设置赋值给当前/ Aap

117、tAssets对象的成员变量mOverlay                if (i>0)                      sp<AaptAssets> nextOver

118、lay = new AaptAssets();                    current->setOverlay(nextOverlay);                 

119、0;  current = nextOverlay;                    current->setFullResPaths(mFullResPaths);               &

120、#160;/ 调用成员函数slurpResourceTree来收录res目录下的资源文件                count = current->slurpResourceTree(bundle, String8(res);             

121、60;  if (count < 0)                     totalCount = count;                &#

122、160;   goto bail;                                totalCount += count; / 统计资源文件个数   &#

123、160;                    else                 fprintf(stderr, "ERROR: '%s' is not&#

124、160;a directoryn", res);                return UNKNOWN_ERROR;                       &

125、#160;            /*     * Now do any additional raw files.     * 接着收录剩余的指定的资源文件 */    for (int arg=0; arg<N;

126、0;arg+)         const char* assetDir = bundle->getFileSpecEntry(arg);        FileType type = getFileType(assetDir);        if (type&

127、#160;= kFileTypeNonexistent)             fprintf(stderr, "ERROR: input directory '%s' does not existn", assetDir);         

128、0;  return UNKNOWN_ERROR;                if (type != kFileTypeDirectory)             fprintf(stderr, "ERROR: &

129、#39;%s' is not a directoryn", assetDir);            return UNKNOWN_ERROR;                String8 assetRoot(assetDir)

130、;        if (bundle->getVerbose()            printf("Processing raw dir '%s'n", (const char*) assetDir);      

131、0; /*         * Do a recursive traversal of subdir tree.  We don't make any         * guarantees about ordering, so 

132、we're okay with an inorder search         * using whatever order the OS happens to hand back to us.         */  

133、0;     count = slurpFullTree(bundle,    assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);        if (count < 0)         

134、;    /* failure; report error and remove archive */            totalCount = count;            goto bail;              

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论