Android 应用包 apk 的内部结构详解

 更新时间:2016年9月20日 20:00  点击:2340

Android应用程序会通过一个工具将应用所有的CLASS文件转换成一个DEX文件,而后Dalvik虚拟机会从其中读取指令和数据。

Android 是Google开发的基于Linux平台的开源手机操作系统,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行,这个系统发布后大大的方便了用户的需求。

每一个Android 应用都运行在一个Dalvik虚拟机实例里,而每一个虚拟机实例都是一个独立的进程空间。虚拟机的线程机制,内存分配和管理。Mutex等等都是依赖底层操作系统而实现的。所有Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制。

不同的应用在不同的进程空间里运行,加之对不同来源的应用都使用不同的Linux用户来运行,可以最大程度的保护应用的安全和独立运行。Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器,每当系统要求执行一个Android应用程序,Zygote就会FORK出一个子进程来执行该应用程序。

这样做的好处显而易见:Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载和初始化等等操作,而在系统需要一个新的虚拟机实例时。Zygote通过复制自身,最快速的提供个系统。另外,对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域,大大节省了内存开销。

应用程序包(APK)被发布到手机上后,运行前会对其中的DEX文件进行优化,优化后的文件被保存到缓存区域(优化后的格式被称为DEY),虚拟机会直接执行该文件。如果应用包文件不发生变化,DEY文件不会被重新生成。

Android应用程序所使用的编程语言是Java语言,和Java SE一样,编译时使用Sun JDK将Java源程序编程成标准的Java字节码文件(.class文件)。而后通过工具软件DX把所有的字节码文件转成DEX文件(classes.dex)。

Android 开发 绘制圆角距形背景实现程序,有需要学习安卓开发的朋友可参考本文章。

需要圆角距形的背景,可是直接用一终圆角的图片,但是因为Android屏幕分辨率太乱,为了能适应所有的分辨率,我们不可能事确定好宽度,虽然可以用draw9patch,但我一直没掌握那工具的用法,做出来的图片最终还是变形,但用下面的方法就永远不会变形,因为没有用图片,是用Android直接绘图.
最终的效果图:

新建一个drawable的xml文件,这里名为server_setting_bg:

 代码如下 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 边缘线的宽度和颜色 -->
    <stroke android:width="1px" android:color="#7d7a7a" />
    <!-- 中间的背景色 -->
    <solid android:color="#e4e4e4"/>
    <!-- 设置四个角的角度 -->
   <corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp"/>
</shape>

 
调用方法:

 代码如下 复制代码

<LinearLayout
 android:layout_width="fill_parent"
android:layout_height="300dp"
 android:layout_marginLeft="10dp"
  android:layout_marginRight="10dp"
 android:layout_marginTop="20dp"
  android:background="@drawable/server_setting_bg"
android:orientation="vertical" >
 </LinearLayout>

Android手机的应用,除了它的手机功能之外,另外一个吸引人的地方在于它的开放性,这一点iphone无法比拟,至少iphone太多商业化气息。android为我们开启另一扇交流之窗,而要实现交流,socket通信必不可少。

java在socket通信方面上已经有了很好的范例,我只是抛砖引玉,将其引入到android之中,疏漏之处在所难免,很多地方也值得深思与考量,高手不必拍砖,可跳过此文。下面,用敲门的方式演示Android如何实现套接字的通信。

服务器程序
服务器程序需要在PC上运行,该程序比较的简单,因此不需要建立Android项目,直接定义一个JAVA类,并且运行该类即可。它仅仅建立ServerSocket监听,并使用Socket获取输入输出流

 代码如下 复制代码

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SimpleServer {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        //创建一个ServerSocket,用于监听客户端socket的连接请求
        ServerSocket ss=new ServerSocket(30000);
        //采用循环不断接受来自客户端的请求,服务器端也对应产生一个Socket
        while(true){
            Socket s=ss.accept();
            OutputStream os=s.getOutputStream();
            os.write("您好,您收到了服务器的新年祝福!n".getBytes("utf-8"));
            os.close();
            s.close();
    }

    }}

客户端程序

 代码如下 复制代码

package my.learn.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;

public class SimpleClient extends Activity {
    private EditText show;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        show = (EditText) findViewById(R.id.show);

        try {

            Socket socket = new Socket("自己计算机的IP地址", 30000);
            //设置10秒之后即认为是超时
            socket.setSoTimeout(10000);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            String line = br.readLine();

            show.setText("来自服务器的数据:"+line);

            br.close();
            socket.close();

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            Log.e("UnknownHost", "来自服务器的数据");
            e.printStackTrace();
        } catch (IOException e) {
            Log.e("IOException", "来自服务器的数据");
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

需要注意的是,在Manifest.xml文件当中,需要对互联网的访问进行授权。

 代码如下 复制代码

<uses-permission  android:name="android.permission.INTERNET"/>

本文章来介绍关于Android应用apk的程序签名详解,关在Android系统中,要求所有应用程序必须经过数字签名后才能安装。Android系统使用这个证书来识别应用程序的作者,并建立程序间的信任关系。

证书并不用让于用户控制可以安装哪些程序,证书也不需要授权中心来签名。在Android系统中,应用程序使用自己签名的证书是完全允许而且是很普遍的。

关于Android应用程序签名主要有以下几个重点:

•所有的应用程序都必须签名。系统不会安装任何一个没有签名的程序。这条规则适用于任何运行Android系统的地方,不管是真机还是模拟器。因此必须在模拟器或真机上运行/调试程序之前对程序进行签名。
•可以使用自己的证书来签名。不需要任何授权中心。
•要为最终用户发布应用程序的时候,必须签入一个合适的密钥。不可以发布程序的时候还使用SDK工具签入的Debug Key。
•系统只在安装应用程序的时候检测证书的有效期。如果应用程序在安装之后证书失效了,应用程序依然可以正常工作。
•可以使用标准工具——Keytool和Jarsigner生成Key并签名apk文件。
•一旦为应用程序签名了,一定要使用zipalign工具来优化最终的APK包。
Debug Key和Release Key
在调试应用程序时,Android SDK工具会自动对应用程序进行了签名。Eclipse的ADT插件和Ant编译工具都提供了两种签名模式——Debug模式和Release模式。 在开发和测试时,可以使用Debug模式。Debug模式下,编译工具使用内嵌在JDK中的Keytool工具来创建一个keystore和一个 key(包含公认的名字和密码)。在每次编译的时候,会使用这个Debug Key来为apk文件签名。由于密码是公认的所以每次编译的时候,并不需要提示你输入keystore和key密码。

当程序准备发布时,必须在Release模式下使用密钥来为apk文件签名。有以下两种方式可以做到:

1. 命令行中使用Keytool和Jarsigner。

这个方法中,首先需要编译出一个未签名的apk。然后使用Jarsigner(或类似的工具),用密钥为apk手动签名。如果没有合适的密钥,可以运行Keytool来手动生成自己的keystore/key。

2. 使用ADT导出向导。

如果使用Eclipse/ADT插件进行开发,可以使用导出向导来编译程序,生成密钥(如果需要),并为apk签名,所有这些操作都在导出向导中。一旦程序签名了,别忘了运行zipalign来为apk进行额外的优化。

关于签名策略
应用程序签名的某些方面可能会影响应用程序的开发,特别是打算一起发布多个应用程序的时候。一般来说,推荐的策略是在整个应用程序寿命内,所有的程序都用相同的证书签名。主要出于以下几点考虑:

•应用程序升级——在应用程序进行升级时,如果想用户平稳的升级,那么就需要签上相同的证书。当系统安装一个升级应用程序时,如果新版本的证书与老版本的证 书有匹配的话,那么,系统才会允许进行升级。如果没有为新版本程序签上合适的证书,那么在安装时需要给应用程序指定一个新的包名。这种情况下,用户安装的 新版本将当作是一个全新的应用程序。
•应用程序模块化——如果应用程序声明,Android系统允许签有相同证书的应用程序运行在相同的进程里。这样系统将会把它们看作是一个单一的应用程序。用这种方法配置应用程序,用户可以选择更新每个独立的模块。
•代码/数据权限共享——Android系统提供了基于签名的权限检查,因此如果应用程序间签有特定的证书,它们之间可以共享功能。通过多个程序签有相同的证书,并且使用基于签名的权限检查,程序可以以一种安全的方式共享代码和数据。
•如果计划支持单个应用程序的升级,需要确保key拥有一个超过期望的应用程序生命周期的有效期。推荐使用25年或更长的有效期。当key过期后,用户也就不能平稳的更新到新的版本了。
•如果给多个无关的应用程序签上了相同的key,那么应确保key的有效期超过所有应用程序所有版本的生命周期,包括将来有可能添加到这一阵营的程序。
•如果想在Android Market上发布程序,key的有效期必须在2033.10.22以后。Market服务器强制这一要求,目的是保证用户可以平稳的更新他们的程序。
在设计应用程序时,一定要考虑以上这些,并使用一个合适的证书来为应用程序签名。

配置签名环境
首先要保证Keytool对SDK编译工具来说是可利用的。一般可以通过设置JAVA_HOME环境变量来告诉SDK编译工具如何找到Keytool。另 外还可以添加JDK中Keytool的路径到PATH的变量里。 如果在Linux上开发,并且使用GNU编译器来编译Java,那么要确保系统是使用JDK中的Keytool,而不是gcj。如果Keytool已经在 PATH中,它有可能是对/usr/bin/keytool的符号链接。这种情况下,要检查符号链接的目标,确保它是指向JDK中的Keytool。

如果要发布应用程序,还需要Jarsigner工具。Jarsigner和Keytool都包含在JDK中。

Debug模式下签名
Android编译工具提供了Debug签名模式,使得开发和调试应用程序更加容易,而且还满足Android系统的签名要求。在使用Debug模式编译 app时,SDK工具会调用Keytool工具自动创建一个Debug的keystore和key。然后这个Debug key会自动用于apk的签名,这样就不需要手动为应用程序包签名了。

关于SDK工具使用的keystore:

•Keystore名字:“debug.keysotre”
•Keystore密码:“android”
•Key别名:“androiddebugkey”
•Key密码:“android”
•CN:“CN=Android Debug,O=Android,C=US”
如果需要可以改变Debug keystore/key的位置和名字,或者提供一个自定义的Debug keysotre/key(在Eclipse/ADT中,通过修改 Windows>Preferences>Android>Build配置实现)。但是任何自定义的Debug keystore/key必须使用和默认Debug key(上面描述的)相同的名字和密码。

注意:不能将签有Debug证书的应用程序发布给最终用户。

Eclipse用户:如果在Eclipse/ADT下开发(并且已经按照上面的描述配置了Keytool),Debug模式下签名默认是开启的。运行或是调试应用程序 时,ADT会使用Debug证书进行签名,并运行zipalign,然后安装到选择的模拟器或是已连接的设备。整个过程不需要人工干预。

Ant用户:如果使用Ant来编译apk文件,则需要在ant命令中添加debug选项来开启Debug签名模式(假设正在使用由android工具生成 build.xml文件)。运行ant debug编译程序时,编译脚本会生成一个keystore/key,并为apk进行签名。然后脚本会使用zipalign工具对apk进行对齐处理。整 个过程不需要人工干预。

Debug证书过期
Debug模式下签名用的证书自从它创建之日起,1年后就会失效。当证书失效时,会得到一个编译错误,Ant上错误如下:

view sourceprint?
1 debug: 

2 [echo] Packaging bin/samples-debug.apk, and signing it with a debug key... 

3 [exec] Debug Certificate expired on 8/4/08 3:43 PM
在Eclipse ADT中,Android控制台上也将会看到一个类似的错误。要解决这个问题,只需删掉debug.keystore文件即可。该文件默认存储的位置在:

•OS X和Linux:~/.android/
•Windows XP:C:/Documents and Settings/.android/
•Windows Vista:C:/Users/.android/
删除后,在下一次编译的时候,编译工具会重新生成一个新的keystore和Debug key。

Release模式下签名
应用程序准备发布给其它用户时,需要:

•获取一个合适的密钥
•在Release模式下编译程序
•使用密钥签名程序
•对齐APK包
如果使用Eclipse ADT插件开发,可以使用导出向导来完成编译、签名和对齐等操作。整个过程中,导出向导还可以生成一个新的keystore和密钥。

关于密钥的生成
为了进行程序签名,必须有一个合适的密钥。这个密钥应有以下特征:

•个人持有。
•代表个人、公司或组织实体的身份。
•有一个有效期。有效期推荐超过25年。在Android Market上发布程序时需要注意:程序的有效期需要在2033.10.22之后。不能上传一个应用程序而它的key的有效期是在这个日期之前。
•不是由Android SDK工具生成的Debug key。
如果没有合适的key,则需要使用Keytool来生成一个。用Keytool生成一个key,可使用keytool命令并传入一些可选参数

今天自己的一个安卓站下载.apk文件时变成了zip可能一直是这样,只是我没发现了,后面网上找一些方法

在Apache安装目录下的conf/mime.types文件的对应位置,加上以下一行语句,指定APK文件的MIME类型为 application/vnd.android.package-archive 即可:

 代码如下 复制代码


application/vnd.android.package-archive     apk;

重启apache即可

分享一些其它的格式的增加方法


找到了个mime的资料,借着张老师的地方分享给大家
下面是各种文件名后缀在nginx的mime.types中的配置:

 代码如下 复制代码
text/vnd.sun.j2me.app-descriptor      jad;
application/java-archive              jar war ear;
application/x-java-archive-diff       jardiff;
application/vnd.android.package-archive apk;
application/vnd.ms-cab-compressed              cab;
application/octet-stream              bin exe dll;
application/vnd.symbian.install       sis;
x-epoc/x-sisx-app                     sisx;
application/iphone                    pxl ipa;
application/vnd.palm                  prc pdb;
application/vnd.webos.ipk             ipk;
application/vnd.rim.cod               cod;
application/mrp                       mrp;
x-nokia-widget                        wgz;
application/octet-stream              deb;
[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
  • Android开发中布局中的onClick简单完成多控件时的监听的利与弊

    本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20
  • Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤

    Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20
  • Android实现简单用户注册案例

    这篇文章主要为大家详细介绍了Android实现简单用户注册案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-26