android app(1)—apk的组成


apk,android package,是一个archive,压缩包文件,包含了一个android app所有的东西。下面对app的运行以及apk中包含的组成部分做简要分析。

运行app

一旦一个apk在设备上安装,每个app运行在自己的security sandbox中。

  1. android系统是一个多用户的linux系统,这里的多用户指的是每个app充当一个用户的角色
  2. system为每个app设置一个unique linux user ID(这个ID只能被system使用,app本身不知道)。
    system为app中的所有files设置权限,因此只有同样user ID的才能去访问他们。
  3. 每个进程都有自己的virtual machine,所以不同进程之间是隔离的。
  4. 每个app都是一个独立的进程。如果该app的任何一个单独组件(activity,service等)需要启动时,系统
    都会将这个进程启动起来。当不在使用时或者内存不足时,关闭这个进程。

基于上面的几点,android系统实现了the principle of lease privilege。就是,每个app默认只访问它运行所需要的components,不能去访问其他东西。这提供一个安全的运行环境,app不能去访问它未授权的东东。

当然,也有方法让app之间共享数据:

  1. 可以把两个app设置为一个uid,这样就能互相访问对方的文件了。此外拥有同样UID的apps可以运行在同一个进程,共享相同的VM(需要用同样的证书签名)。
  2. app可以申请权限去获取设备的数据,例如用户的联系人、短信、camera、蓝牙等。

app中的组件

app的components是app组成的基本元素。每个component是一个不同的切入点,通过每个切入点system可以启动该app。不是所有的components都是实际的entry points,可能其中一个依赖与另一个,但是每个components都扮演着自己独特的角色,不可或缺。
下面是android中的四大组件。

Activity

每个activity代表了一个单独的用户界面。例如,一个email app可能有一个activity用来显示新emails的列表,另外一个activity用来发送邮件。虽然很多个activity一起协同工作,使用户感觉这个email app是一个整体的执行过程,但是每个activity都是独立的。其他app可以启动email app中的任何一个acvity(当然得有权限)。例如一个camera app可以启动一个email app中 的activity去写邮件,将刚拍摄的照片通过邮件发送出去。

Services

不同于activity,service是运行在后台的,适用于长时间运行的操作,或者为其他进程提供服务。service没有用户界面,例如,一个service可能在后台播放音乐,而用户当时正在浏览另外一个app;或者在后台跟网络交互获取数据而不会去阻塞用户和activity直接的交互。其他的component,例如activity,可以启动service,或者绑定到service用来和service之间交互。

Content providers

前面两个组件,一个前台,一个后台。而content provider管理app的共享数据。你可以将app的数据保存到文件系统、SQLite数据库、web、或者其他persistent storage location,只要你的app可以访问到。通过content provider,其他app可以query、甚至修改数据(只要content provider允许)。例如,androdir系统提供了管理联系人的content provider。因此,其他拥有对应权限的app则可以query这个content provider,读取和修改一个人的信息。

Broadcast receivers

broadcast receiver是对系统范围的广播的响应。android中很多广播都是由系统发出的,例如,一个广播通知屏幕关闭了,电量低。当然app也可以发送广播,例如,通知其他app一些数据已经下载完成,可以去使用了。虽然broadcast receiver不提供用户界面,但是可能会创建一个status bar notification,提醒用户。broadcast receiver更普遍的用法是启动其他components的gateway。例如,当收到广播后,启动一个service去做相应的事情。

组件的启动

android系统的一个独一无二的创新设计思想:任何app可以去启动另外app的component。例如,如果一个用户想去通过camera捕获一副图片,已经有其他app实现了这个功能,所以你不需要自己开发一个activity去捕获图形,甚至你的code不用link到camera app。你可以在自己的activity中直接跳转到camera app捕获图形的activity。等图片捕获完成后,结果返回给你自己的app。而对于用户使用,看起来好像camera app就像是你app中的一部分。

当system启动一个app的某一component,它会启动app对应的进程(如果进程未运行)。例如,当你的app启动camera app中的activity去捕获图片,会去启动camera app的进程,这个activity是在camera app的进程中运行,而和你的app没关系。每个app在各自的进程中运行,并且有权限限制去accsess其他app。所以你的app不是直接去启动其他app的component,是通过system完成。首先你发送一个msg给system,system然后去帮你完成。

四大组件中的三个,activity,service,broadcast receiver的启动都是通过一种异步message,称为intent。intent由Intent对象产生,定义了需要启动某一个app的某一个component或者某一种类型的component。

对activity和service而言,一个intent定义了要去执行的动作(例如,view or send something),可能会利用
URI指定需要操作的数据。例如,一个intent可能会去启动某activity去显示一副图片或者打开一个网页。
在某些情况,还能通过intent返回数据。(例如,一个intent让用户去选择一个用户联系人,然后把它返回给用户去做修改,返回的intent包括一个URI指向选定的联系人信息)。

对broadcast receivers,intent只是简单的定义了将要被广播的事件。(例如,一个说明电池电量低的广播仅仅包含表明“电池电量低”的action字符串,ACTION_BATTERY_LOW)。

对content provider,不是用intent去触发的,而是通过一个ContentResolver的请求。

四大组件的触发方法:

   /*
    You can start an activity (or give it something new to do) by passing an Intent to startActivity() or startActivityForResult() (when you want the activity to return a result).

    You can start a service (or give new instructions to an ongoing service) by passing an Intent to startService(). Or you can bind to the service by passing an Intent to bindService().

    You can initiate a broadcast by passing an Intent to methods like sendBroadcast(), sendOrderedBroadcast(), or sendStickyBroadcast().

    You can perform a query to a content provider by calling query() on a ContentResolver.
    */

app中的Manifest文件

在系统运行一个app的某一组件之前,系统必须通过读取AndroidManifest.xml文件知道这个app的所有组件。app必须在manifest文件中声明它所有的components,manifest文件文件放在app工程的根目录下。
除了声明app的组件外,manifest文件中还包括:
app所需要的权限,例如联网和读取联系人;
声明最低的API Level;
声明这个app运行所需要的软件和硬件features,例如得有camera,bluetooth等;
app需要链接的库,例如google maps library;
…..

声明组件

manifest文件的主要作用就是告诉system app所包含的组件。例如

    <?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:icon="@drawable/app_icon.png" ... >
        <activity android:name="com.example.project.ExampleActivity"
                  android:label="@string/example_label" ... >
        </activity>
        ...
    </application>
</manifest>

在application标签内,android:icon属性指示了app图标的资源文件。
在activity标签内,android:name属性指示了Activity子类的类名,而android:label属性指示了该activity所
对应的用户可读的一个string。

/*
You must declare all app components this way:

    <activity> elements for activities
    <service> elements for services
    <receiver> elements for broadcast receivers
    <provider> elements for content providers
*/

activitys,services,content providers如果你只是在代码中定义而没有在manifest文件中声明,system是不知道的,导致的结果就是无法运行。而broadcast receivers即可以在manifest中声明也可以在代码中创建(created dynamically in code (as BroadcastReceiver objects) and registered with the system by calling registerReceiver())

声明组件capabilities

前面分析过,在启动其他components时,你可以利用Intent,显示指明需要启动的component(利用该component的类名)。但是intent的真正强大之处在于 implicit intents, implicit intents简单的描述将要执行的action type(可选择的,action所对应的data),然后让系统去查找符合这个action的component去执行。如果有多个components能够执行这个intent中描述的action,用户自己选择一个去执行。
system判断一个component是否能够响应一个intent的方法是:比较收到的intent和manifest中的intent fliters.
例如,如果你创建了一个email app,里面有一个写email的activity,你可以声明一个intent filter去响应 “send” intents。

<manifest ... >
    ...
    <application ... >
        <activity android:name="com.example.project.ComposeEmailActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <data android:type="*/*" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

如果有其他app创建了一个intent,有ACTION_SEND action,然后把这个intent传给startActivity()函数,
系统就会启动email的activity。

声明app requirements

由于android支持很多设备,设备的硬件、软件都是有差距的,所以你需要在manifest声明自己app的硬件、软件需求。这些信息android system一般不去读取他们,但是会把google play这种应用商店读取,在你去应用商店搜索app时做出过滤。
例如,你的app需要一个camera,同时使用API Level7,你需要在manifest中做如下声明:

<manifest ... >
    <uses-feature android:name="android.hardware.camera.any"
                  android:required="true" />
    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
    ...
</manifest>

这样,对没有camera和Android version 低于2.1的设备就无法安装你这app。

app中的资源文件

android将所有的资源文件和源代码分离开,这样可以使app适用多种场景,例如多语言和不同分辨率(提供
多语言的资源、多尺寸的资源)。
对每一个添加进系统的资源文件,SDK build tool会为其定义一个独一无二的整数ID,在源代码中你就能通过这个ID对该资源文件进行引用。例如logo.png保存在res/drawable/下,SDK tool会产生一个资源ID R.drawable.logo,在源代码中就可以使用该资源了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值