【Android学习】apk生成及安装

1,概念

1)Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为资源打包和代码打包。

2,打包流程

打包流程
1)通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文件。
2)通过AIDL工具处理AIDL文件,生成相应的Java文件。
3)通过Javac工具编译项目源码,生成Class文件。
4)通过DX工具将所有的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。
5)通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。
6)利用KeyStore对生成的APK文件进行签名。
7)如果是正式版的APK,还会利用ZipAlign工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件的速度会更快。

3,APK的安装流程

apk的安装流程
1)复制APK到/data/app目录下,解压并扫描安装包。
2)资源管理器解析APK里的资源文件。
3)解析AndroidManifest文件,并在/data/data/目录下创建对应的应用数据目录。
4)然后对dex文件进行优化,并保存在dalvik-cache目录下。
5)将AndroidManifest文件解析出的四大组件信息注册到PackageManagerService中。
6)安装完成后,发送广播。

4,app启动过程

点击应用图标后会去启动应用的LauncherActivity,如果LancerActivity所在的进程没有创建,还会创建新进程,整体的流程就是一个Activity的启动流程。
app启动过程

1)主要角色

①Instrumentation
监控应用与系统相关的交互行为。
②AMS
组件管理调度中心,什么都不干,但是什么都管。
③ActivityStarter
Activity启动的控制器,处理Intent与Flag对Activity启动的影响,具体说来有:
1 寻找符合启动条件的Activity,如果有多个,让用户选择;
2 校验启动参数的合法性;
3 返回int参数,代表Activity是否启动成功。
④ActivityStackSupervisior
这个类的作用你从它的名字就可以看出来,它用来管理任务栈。
这是高版本才有的类,它用来管理多个ActivityStack,早期的版本只有一个ActivityStack对应着手机屏幕,后来高版本支持多屏以后,就有了多个ActivityStack,于是就引入了ActivityStackSupervisior用来管理多个ActivityStack。
⑤ActivityStack
用来管理任务栈里的Activity。
⑥ActivityThread
最终干活的人,是ActivityThread的内部类,Activity、Service、BroadcastReceiver的启动、切换、调度等各种操作都在这个类里完成。

2)相关进程

①调用者进程

如果是在桌面启动应用就是Launcher应用进程。

②ActivityManagerService等所在的System Server进程

该进程主要运行着系统服务组件。

③Zygote进程

该进程主要用来fork新进程。

④新启动的应用进程

该进程就是用来承载应用运行的进程了,它也是应用的主线程(新创建的进程就是主线程),处理组件生命周期、界面绘制等相关事情。

3)整个流程

①点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。
②AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack
③处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。
Zygote接收到新进程创建请求后fork出新进程。
④在新进程里创建ActivityThread对象,新创建的进程就是应用的主线程,在主线程里开启Looper消息循环,开始处理创建Activity。
⑤ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法。这样便完成了Activity的启动。

5,类加载器

1)PathClassLoader

只能加载已经安装到Android系统的APK文件,即/data/app目录,Android默认的类加载器。

2)DexClassLoader

可以加载任意目录下的dex、jar、apk、zip文件。

6,64k方法

1)问题

随着功能的增加,方法数增多,就会出现所谓的64k方法数问题。

2)产生原因

Android APK文件本质上是一个压缩文件,它包含的classes.dex文件是Dalvik字节码文件,这个dex文件中存放的就是编译后的Java代码。Dalvik可执行文件规范限制了单个.dex文件最多引用的方法数是65536个。

在DEX文件中,method、field、class等的个数使用short类型来做索引,即两个字节(65535),method、field、class等均有此限制。

APK在安装过程中会调用dexopt将DEX文件优化成ODEX文件,dexopt使用LinearAlloc来存储应用信息,关于LinearAlloc缓冲区大小,不同的版本经历了4M/8M/16M的限制,超出缓冲区时就会抛出INSTALL_FAILED_DEXOPT错误。

3)解决方案–MultiDex的使用

google为了规避上述问题,推出了MultiDex解决方案解决方法数超限问题,可以配置方法数超过 64K 的应用。

4)解决原理

①Android5.0之前
Dalvik在5.0之前,为每一个APK只生成一个classes.dex,所以会有上述所说的方法数超限的问题,如果我们可以将一个dex文件分成多个,在应用启动时,加载第一个(主dex)dex文件,当启动以后,再依次加载其他dex文件。这样就可以规避上述问题了。MultiDex即是实现了这样的功能
②Android5.0之后
Android5.0及更高版本使用支持从apk中加载多个dex文件的ART运行时机制,在应用安装时,加载classed(…N).dex文件并编译成一个.oat文件以支持在Android设备上运行。

5)实现

配置build.gradle

android {
      compileSdkVersion 21
      buildToolsVersion "21.1.0"//必须使用21或之后的版本
      defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...


        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
  }
  dependencies {
  compile 'com.android.support:multidex:1.0.0'
  }

配置Application
如果用户没有重写Application,只需修改Manifest文件中的内容:

<application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>

如果用户继承变重写了Application,可以将继承的Application换成MultiDexApplication。
或者重写attachBaseContext() 方法,

@Override
 protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
}

特别注意,如果没有实现这部分代码,运行时会出现NoClassDefFoundError的错误,尤其是在依赖三方函数库时。
这个问题之前出现过很多次,当时是由于配置了build.gradle文件但是没有使用MultiDexApplication造成的。所以开发者一定要记得使用MultiDexApplication或者MultiDex.install(this),具体参考上面提到过的配置Application。

还有一种情况,上面提到过的,使用MultiDex机制,必然存在主dex文件和从dex文件,应用启动时所需要的类,都应放入主dex中,否则也会出现NoClassDefFoundError。这种情况可以手动添加一些类到主dex中:

multiDexKeepFile
手动加入要放到Main.dex中的类。

android/support/multidex/MultiDex.class

multiDexKeepProguard
以Proguard的方式手动加入要放到Main.dex中的类。

-keep class android.support.multidex.** {
    *;
}

然后在build.gradle中进行配置:

android {
    defaultConfig {
        multiDexEnabled true
        multiDexKeepProguard file('multiDexKeep.pro') 
        multiDexKeepFile file('multiDexKeep.txt') 
    }
}
dependencies {
    compile'com.android.support:multidex:1.0.1'
}

6)Multidex优化

multidex会加长构建应用的时间,这个必要的过程可能会拖慢你的开发进度。 为加速构建过程,我们可以在Gradle中配置productFlavors。
开发时将minSdkVersion改为21使用ART运行时机制,这样能加快构建速度。release时改为合适的minSdkVersion,这样仅在release时费时较长。
build.gradle配置如下:

android {
        productFlavors {
            dev {
                minSdkVersion 21
            }
            prod {
                minSdkVersion 14
            }
        }
              ...
        buildTypes {
            release {
             ...
            }
        }
    }
    dependencies {
      compile 'com.android.support:multidex:1.0.0'
    }

完成上述配置后,你可以使用结合了dev productFlavor和buildType属性的devDebug变体app。
这个变体app包含如下特性:

关闭了混淆(proguard)
支持multidex
minSdkVersion 设置为 Android API level 21.
值得注意的是:上述配置后的devDebug变种app仅能运行在Android 5.0设备上。

猜你喜欢

转载自blog.csdn.net/sunshinetan/article/details/79980223