android手动打包
‘壹’ Android开发问题:Failed to install Hello.apk on device 'emulator-5554!
R.java消失或解析异常
自定义title栏
SQLite isFirst和isBeforeFirst方法的区别
eclipse删除空行
getX()和getRawX()的区别
imagView居中显示问题
synchronized引发了 java.util.
获取随机颜色
去掉Activity的标题栏,全屏显示
如何修改应用名称及应用图标
关于调试方法
Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
android.content.res.Resources.loadXmlResourceParser
android.content.res.Resources$NotFoundException
交互性的button定义的方法
在超级终端中执行程序报错-Permission deny
从svn导入工程项目有惊叹号
从svn导入工程项目有惊叹号
首次进入带有EditText的Activity不自动弹出软键盘,再次点击才弹
Gallery中OnItemClickListener与OnItemSelectedListener的区别
Eclipse中签名导出apk崩溃,手动签名
android.view.InflateException: Binary XML file line #异常的解决
判断是否有root权限
最简单的Root 模拟器的方法
新版ADT开启eclipse提示 "Running Android Lint" has encountered a problem
新版ADT开启eclipse提示cannot open libstdc++.so.6..
无法升级ADT
‘贰’ android如何使用ant批量打包
ps :后期熟悉ant的话,可以使用纯ant脚本或者使用另一种更好的自动化打包工具(maven)关键代码如下:package com.cn.ant; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import org.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; public class AntTest { private Project project; public void init(String _buildFile, String _baseDir) throws Exception { project = new Project(); project.init(); DefaultLogger consoleLogger = new DefaultLogger(); consoleLogger.setErrorPrintStream(System.err); consoleLogger.setOutputPrintStream(System.out); consoleLogger.setMessageOutputLevel(Project.MSG_INFO); project.addBuildListener(consoleLogger); // Set the base directory. If none is given, "." is used. if (_baseDir == null) _baseDir = new String("."); project.setBasedir(_baseDir); if (_buildFile == null) _buildFile = new String(projectBasePath + File.separator + "build.xml"); //ProjectHelper.getProjectHelper().parse(project, new File(_buildFile)); // 关键代码 ProjectHelper.configureProject(project, new File(_buildFile)); } public void runTarget(String _target) throws Exception { // Test if the project exists if (project == null) throw new Exception( "No target can be launched because the project has not been initialized. Please call the 'init' method first !"); // If no target is specified, run the default one. if (_target == null) _target = project.getDefaultTarget(); // Run the target project.executeTarget(_target); } // private final static ArrayList<String> flagList = new ArrayList<String>(); //也可以使用集合,不过需要手动添加项 private final static String[] flagList = new String[]{"htc","moto","oppo"};//此处初始化市场标识 private final static String projectBasePath = ""; //项目的根目录,需要配置 private final static String ApkPath = ""; //要改名后拷贝的目录,需要配置 private final static String placeHolder = ""; //占位符,需要配置 public static void main(String args[]) { //flagList.add("htc"); //flagList.add("moto"); //flagList.add("oppo"); try { System.out.println("---------ant批量自动化打包开始----------"); for(String flag : flagList){ //先修改manifest文件:读取临时文件中的@market@修改为市场标识,然后写入manifest.xml中 String tempFilePath = projectBasePath + File.separator + "AndroidManifest.xml.temp"; String filePath = projectBasePath + File.separator + "AndroidManifest.xml"; write(filePath,read(tempFilePath, flag)); //执行打包命令 AntTest mytest = new AntTest(); mytest.init( projectBasePath + File.separator + "build.xml", projectBasePath); mytest.runTarget("clean"); mytest.runTarget("release"); //打完包后执行重命名加拷贝操作 //String flag = "htc"; File file = new File(projectBasePath + File.separator +"bin"+File.pathSeparator+"MainActivity-release.apk");//bin目录下签名的apk文件 file.renameTo(new File(ApkPath + File.separator + "MainActivity_"+flag+".apk")); } System.out.println("---------ant批量自动化打包结束----------"); } catch (Exception e) { e.printStackTrace(); System.out.println("---------ant批量自动化打包中发生异常----------"); } } public static String read(String filePath,String replaceStr) { BufferedReader br = null; String line = null; StringBuffer buf = new StringBuffer(); try { // 根据文件路径创建缓冲输入流 br = new BufferedReader(new FileReader(filePath)); // 循环读取文件的每一行, 对需要修改的行进行修改, 放入缓冲对象中 while ((line = br.readLine()) != null) { // 此处根据实际需要修改某些行的内容 if (line.contains(placeHolder)) { line = line.replace(placeHolder, replaceStr); buf.append(line); } else { buf.append(line); } buf.append(System.getProperty("line.separator")); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭流 if (br != null) { try { br.close(); } catch (IOException e) { br = null; } } } return buf.toString(); } /** * 将内容回写到文件中 * * @param filePath * @param content */ public static void write(String filePath, String content) { BufferedWriter bw = null; try { // 根据文件路径创建缓冲输出流 bw = new BufferedWriter(new FileWriter(filePath)); // 将内容写入文件中 bw.write(content); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭流 if (bw != null) { try { bw.close(); } catch (IOException e) { bw = null; } } } } }
‘叁’ Android应用手动签名打包的apk无法在手机上安装,而自动用debug签名的apk包安装就没题
应该是proguard.cfg文件缺东西
‘肆’ 如何打包安卓手机Zip升级包如何签名不换Recovery,用官方Recovery
通过分析update.zip包在具体Android系统升级的过程,来理解Android系统中Recovery模式服务的工作原理。
我们先从update.zip包的制作开始,然后是Android系统的启动模式分析,Recovery工作原理,如何从我们上层开始选择system update到重启到Recovery服务,以及在Recovery服务中具体怎样处理update.zip包升级的,我们的安装脚本updater-script怎样被解析并执行的等一系列问题。分析过程中所用的Android源码是gingerbread0919(tcc88xx开发板标配的),测试开发板是tcc88xx。
一、 update.zip包的目录结构
|----boot.img
|----system/
|----recovery/
`|----recovery-from-boot.p
`|----etc/
`|----install-recovery.sh
|---META-INF/
`|CERT.RSA
`|CERT.SF
`|MANIFEST.MF
`|----com/
`|----google/
`|----android/
`|----update-binary
`|----updater-script
`|----android/
`|----metadata
二、 update.zip包目录结构详解
以上是我们用命令make otapackage 制作的update.zip包的标准目录结构。
1、boot.img是更新boot分区所需要的文件。这个boot.img主要包括kernel+ramdisk。
2、system/目录的内容在升级后会放在系统的system分区。主要用来更新系统的一些应用或则应用会用到的一些库等等。可以将Android源码编译out/target/proct/tcc8800/system/中的所有文件拷贝到这个目录来代替。
3、recovery/目录中的recovery-from-boot.p是boot.img和recovery.img的补丁(patch),主要用来更新recovery分区,其中etc/目录下的install-recovery.sh是更新脚本。
4、update-binary是一个二进制文件,相当于一个脚本解释器,能够识别updater-script中描述的操作。该文件在Android源码编译后out/target/proct/tcc8800/system bin/updater生成,可将updater重命名为update-binary得到。
该文件在具体的更新包中的名字由源码中bootable/recovery/install.c中的宏ASSUMED_UPDATE_BINARY_NAME的值而定。
5、updater-script:此文件是一个脚本文件,具体描述了更新过程。我们可以根据具体情况编写该脚本来适应我们的具体需求。该文件的命名由源码中bootable/recovery/updater/updater.c文件中的宏SCRIPT_NAME的值而定。
6、 metadata文件是描述设备信息及环境变量的元数据。主要包括一些编译选项,签名公钥,时间戳以及设备型号等。
7、我们还可以在包中添加userdata目录,来更新系统中的用户数据部分。这部分内容在更新后会存放在系统的/data目录下。
8、update.zip包的签名:update.zip更新包在制作完成后需要对其签名,否则在升级时会出现认证失败的错误提示。而且签名要使用和目标板一致的加密公钥。加密公钥及加密需要的三个文件在Android源码编译后生成的具体路径为:
out/host/linux-x86/framework/signapk.jar
build/target/proct/security/testkey.x509.pem
build/target/proct/security/testkey.pk8 。
我们用命令make otapackage制作生成的update.zip包是已签过名的,如果自己做update.zip包时必须手动对其签名。
具体的加密方法:$ java –jar gingerbread/out/host/linux/framework/signapk.jar –w gingerbread/build/target/proct/security/testkey.x509.pem gingerbread/build/target/proct/security/testkey.pk8 update.zip update_signed.zip
以上命令在update.zip包所在的路径下执行,其中signapk.jar testkey.x509.pem以及testkey.pk8文件的引用使用绝对路径。update.zip 是我们已经打好的包,update_signed.zip包是命令执行完生成的已经签过名的包。
9、MANIFEST.MF:这个manifest文件定义了与包的组成结构相关的数据。类似Android应用的mainfest.xml文件。
10、CERT.RSA:与签名文件相关联的签名程序块文件,它存储了用于签名JAR文件的公共签名。
11、CERT.SF:这是JAR文件的签名文件,其中前缀CERT代表签名者。
另外,在具体升级时,对update.zip包检查时大致会分三步:①检验SF文件与RSA文件是否匹配。②检验MANIFEST.MF与签名文件中的digest是否一致。③检验包中的文件与MANIFEST中所描述的是否一致。
三、 Android升级包update.zip的生成过程分析
1) 对于update.zip包的制作有两种方式,即手动制作和命令生成。
第一种手动制作:即按照update.zip的目录结构手动创建我们需要的目录。然后将对应的文件拷贝到相应的目录下,比如我们向系统中新加一个应用程序。可以将新增的应用拷贝到我们新建的update/system/app/下(system目录是事先拷贝编译源码后生成的system目录),打包并签名后,拷贝到SD卡就可以使用了。这种方式在实际的tcc8800开发板中未测试成功。签名部分未通过,可能与具体的开发板相关。
第二种制作方式:命令制作。Android源码系统中为我们提供了制作update.zip刷机包的命令,即make otapackage。该命令在编译源码完成后并在源码根目录下执行。 具体操作方式:在源码根目录下执行
①$ . build/envsetup.sh。
②$ lunch 然后选择你需要的配置(如17)。
③$ make otapackage。
在编译完源码后最好再执行一遍上面的①、②步防止执行③时出现未找到对应规则的错误提示。命令执行完成后生成的升级包所在位置在out/target/proct/full_tcc8800_evm_target_files-eng.mumu.20120309.111059.zip将这个包重新命名为update.zip,并拷贝到SD卡中即可使用。
这种方式(即完全升级)在tcc8800开发板中已测试成功。
2) 使用make otapackage命令生成update.zip的过程分析。
在源码根目录下执行make otapackage命令生成update.zip包主要分为两步,第一步是根据Makefile执行编译生成一个update原包(zip格式)。第二步是运行一个python脚本,并以上一步准备的zip包作为输入,最终生成我们需要的升级包。下面进一步分析这两个过程。
第一步:编译Makefile。对应的Makefile文件所在位置:build/core/Makefile。从该文件的884行(tcc8800,gingerbread0919)开始会生成一个zip包,这个包最后会用来制作OTA package 或者filesystem image。先将这部分的对应的Makefile贴出来如下:
[python] view plainprint?
# -----------------------------------------------------------------
# A zip of the directories that map to the target filesystem.
# This zip can be used to create an OTA package or filesystem image
# as a post-build step.
#
根据上面的Makefile可以分析这个包的生成过程:
首先创建一个root_zip根目录,并依次在此目录下创建所需要的如下其他目录
①创建RECOVERY目录,并填充该目录的内容,包括kernel的镜像和recovery根文件系统的镜像。此目录最终用于生成recovery.img。
②创建并填充BOOT目录。包含kernel和cmdline以及pagesize大小等,该目录最终用来生成boot.img。
③向SYSTEM目录填充system image。
④向DATA填充data image。
⑤用于生成OTA package包所需要的额外的内容。主要包括一些bin命令。
⑥创建META目录并向该目录下添加一些文本文件,如apkcerts.txt(描述apk文件用到的认证证书),misc_info.txt(描述Flash内存的块大小以及boot、recovery、system、userdata等分区的大小信息)。
⑦使用保留连接选项压缩我们在上面获得的root_zip目录。
⑧使用fs_config(build/tools/fs_config)配置上面的zip包内所有的系统文件(system/下各目录、文件)的权限属主等信息。fs_config包含了一个头文件#include“private/android_filesystem_config.h”。在这个头文件中以硬编码的方式设定了system目录下各文件的权限、属主。执行完配置后会将配置后的信息以文本方式输出 到META/filesystem_config.txt中。并再一次zip压缩成我们最终需要的原始包。
第二步:上面的zip包只是一个编译过程中生成的原始包。这个原始zip包在实际的编译过程中有两个作用,一是用来生成OTA update升级包,二是用来生成系统镜像。在编译过程中若生成OTA update升级包时会调用(具体位置在Makefile的1037行到1058行)一个名为ota_from_target_files的python脚本,位置在/build/tools/releasetools/ota_from_target_files。这个脚本的作用是以第一步生成的zip原始包作为输入,最终生成可用的OTA升级zip包。
二 下面我们分析ota_from_target_files这个python脚本是怎样生成最终zip包的。先讲这个脚本的代码贴出来如下:
[python] view plainprint?
import sys
if sys.hexversion < 0x02040000:
print >> sys.stderr, "Python 2.4 or newer is required."
sys.exit(1)
主函数main是python的入口函数,我们从main函数开始看,大概看一下main函数(脚本最后)里的流程就能知道脚本的执行过程了。
① 在main函数的开头,首先将用户设定的option选项存入OPTIONS变量中,它是一个python中的类。紧接着判断有没有额外的脚本,如果有就读入到OPTIONS变量中。
② 解压缩输入的zip包,即我们在上文生成的原始zip包。然后判断是否用到device-specific extensions(设备扩展)如果用到,随即读入到OPTIONS变量中。
③ 判断是否签名,然后判断是否有新内容的增量源,有的话就解压该增量源包放入一个临时变量中(source_zip)。自此,所有的准备工作已完毕,随即会调用该 脚本中最主要的函数WriteFullOTAPackage(input_zip,output_zip)
④ WriteFullOTAPackage函数的处理过程是先获得脚本的生成器。默认格式是edify。然后获得metadata元数据,此数据来至于Android的一些环境变量。然后获得设备配置参数比如api函数的版本。然后判断是否忽略时间戳。
⑤ WriteFullOTAPackage函数做完准备工作后就开始生成升级用的脚本文件(updater-script)了。生成脚本文件后将上一步获得的metadata元数据写入到输出包out_zip。
⑥至此一个完整的update.zip升级包就生成了。生成位置在:out/target/proct/tcc8800/full_tcc8800_evm-ota-eng.mumu.20120315.155326.zip。将升级包拷贝到SD卡中就可以用来升级了。
四、 Android OTA增量包update.zip的生成
在上面的过程中生成的update.zip升级包是全部系统的升级包。大小有80M多。这对手机用户来说,用来升级的流量是很大的。而且在实际升级中,我们只希望能够升级我们改变的那部分内容。这就需要使用增量包来升级。生成增量包的过程也需要上文中提到的ota_from_target_files.py的参与。
下面是制作update.zip增量包的过程。
① 在源码根目录下依次执行下列命令
$ . build/envsetup.sh
$ lunch 选择17
$ make
$ make otapackage
执行上面的命令后会在out/target/proct/tcc8800/下生成我们第一个系统升级包。我们先将其命名为A.zip
② 在源码中修改我们需要改变的部分,比如修改内核配置,增加新的驱动等等。修改后再一次执行上面的命令。就会生成第二个我们修改后生成的update.zip升级包。将 其命名为B.zip。
③ 在上文中我们看了ota_from_target_files.py脚本的使用帮助,其中选项-i就是用来生成差分增量包的。使用方法是以上面的A.zip 和B.zip包作为输入,以update.zip包作 为输出。生成的update.zip就是我们最后需要的增量包。
具体使用方式是:将上述两个包拷贝到源码根目录下,然后执行下面的命令。
$ ./build/tools/releasetools/ota_from_target_files -i A.zip B.zip update.zip。
在执行上述命令时会出现未找到recovery_api_version的错误。原因是在执行上面的脚本时如果使用选项i则会调用WriteIncrementalOTAPackage会从A包和B包中的META目录下搜索misc_info.txt来读取recovery_api_version的值。但是在执行make otapackage命令时生成的update.zip包中没有这个目录更没有这个文档。
此时我们就需要使用执行make otapackage生成的原始的zip包。这个包的位置在out/target/proct/tcc8800/obj/PACKAGING/target_files_intermediates/目录下,它是在用命令make otapackage之后的中间生产物,是最原始的升级包。我们将两次编译的生成的包分别重命名为A.zip和B.zip,并拷贝到SD卡根目录下重复执行上面的命令:
$ ./build/tools/releasetools/ota_form_target_files -i A.zip B.zip update.zip。
在上述命令即将执行完毕时,在device/telechips/common/releasetools.py会调用IncrementalOTA_InstallEnd,在这个函数中读取包中的RADIO/bootloader.img。
而包中是没有这个目录和bootloader.img的。所以执行失败,未能生成对应的update.zip。可能与我们未修改bootloader(升级firmware)有关。此问题在下一篇博客已经解决。
制作增量包失败的原因,以及解决方案。
Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的解决
在上一篇末尾提到的生成差分包时出现的问题,现已解决,由于最近比较忙,相隔的时间也比较长,所以单列一个篇幅提示大家。这个问题居然是源码中的问题,可能你已经制作成功了,不过我的这个问题确实是源码中的一个问题,不知道是不是一个bug,下文会具体分析!
一、生成OTA增量包失败的解决方案
在上一篇中末尾使用ota_from_target_files脚本制作update.zip增量包时失败,我们先将出现的错误贴出来。
在执行这个脚本的最后读取input_zip中RADIO/bootloader.img时出现错误,显示DeviceSpecifiParams这个对象中没有input_zip属性。
我们先从脚本中出现错误的调用函数中开始查找。出现错误的调用地方是在函WriteIncrementalOTAPackage(443行)中的device_specific.IncrementalOTA_InstallEnd(),其位于WriteIncrementalOTAPackage()中的末尾。进一步跟踪源码发现,这是一个回调函数,他的具体执行方法位于源码中/device/telechips/common/releasetools.py脚本中的IncrementalOTA_InstallEnd()函数。下面就分析这个函数的作用。
releasetools.py脚本中的两个函数FullOTA_InstallEnd()和IncrementalOTA_InstallEnd()的作用都是从输入包中读取RADIO/下的bootloader.img文件写到输出包中,同时生成安装bootloader.img时执行脚本的那部分命令。只不过一个是直接将输入包中的bootloader.img镜像写到输出包中,一个是先比较target_zip和source_zip中的bootloader.img是否不同(使用选项-i生成差分包时),然后将新的镜像写入输出包中。下面先将这个函数(位于/device/telechips/common/releasetools.py)的具体实现贴出来:
我们的实际情况是,在用命令make otapackage时生成的包中是没有这个RADIO目录下的bootloader.img镜像文件(因为这部分更新已被屏蔽掉了)。但是这个函数中对于从包中未读取到bootloader.img文件的情况是有错误处理的,即返回。所以我们要从 出现的实际错误中寻找问题的原由。
真正出现错误的地方是:
target_bootloader=info.input_zip.read(“RADIO/bootloader.img”)。
出现错误的原因是:AttributeError:‘DeviceSpecificParams’object has no attribute ‘input_zip’,提示我们DeviceSpecificParams对象没有input_zip这个属性。
二、updater-script脚本执行流程分析:
先看一下在测试过程中用命令make otapackage生成的升级脚本如下:
[python] view plainprint?
assert(!less_than_int(1331176658, getprop("ro.build.date.utc")));
assert(getprop("ro.proct.device") == "tcc8800" ||
下面分析下这个脚本的执行过程:
①比较时间戳:如果升级包较旧则终止脚本的执行。
②匹配设备信息:如果和当前的设备信息不一致,则停止脚本的执行。
③显示进度条:如果以上两步匹配则开始显示升级进度条。
④格式化system分区并挂载。
⑤提取包中的recovery以及system目录下的内容到系统的/system下。
⑥为/system/bin/下的命令文件建立符号连接。
⑦设置/system/下目录以及文件的属性。
⑧将包中的boot.img提取到/tmp/boot.img。
⑨将/tmp/boot.img镜像文件写入到boot分区。
⑩完成后卸载/system。
三、总结
以上的九篇着重分析了Android系统中Recovery模式中的一种,即我们做好的update.zip包在系统更新时所走过的流程。其核心部分就是Recovery服务的工作原理。其他两种FACTORY RESET、ENCRYPTED FILE SYSTEM ENABLE/DISABLE与OTA INSTALL是相通的。重点是要理解Recovery服务的工作原理。另外详细分析其升级过程,对于我们在实际升级时,可以根据我们的需要做出相应的修改。
‘伍’ 如何手动安装apk(不使用打包安装程序和应用商店的root快速安装等方法)我对Android有一
可能直接用命令安装,首先准备需要安装的apk文件
然后执行以下步骤:
1.将需要安装的apk文件放在和adb应用程序的同一个文件夹中。
2.打开cmd应用程序窗口。
3.用命令进入adb的系统文件夹里面。
4.使用命令adb install xxx.apk 回车,接下来就是等待安装。安装好之后会返回success。
‘陆’ 如何将资源打包到 /data/data/PackageName/files/ 目录下
这个很好弄啊!你可以把文件放在assets文件夹里面,然后直接从assets文件夹里面拷贝到/data/data/package/files/目录下面就成了啊!
‘柒’ android app调试没问题,但打包签名的apk,运行时出现闪退怎么办
.找到Project -> Build Automatically,取消它关闭自动编译
2.然后Clean一下
3.最后在手动Build一下
然后你再打包签名,这样就可以正常运行了。
‘捌’ 我打包android apk 安装新版本的时候为什么必须卸载之前卸载的版本
不是卸载之前的版本,是新版本覆盖之前的版本,同一个版本包名一致就会覆盖,你可以试下换个包名再安装
‘玖’ android studio 打包谁会
1)手动打包
项目写完了,现在需要把应用上传到市场,问题出现—怎么把代码变成.apk(Android的可安装文件)。
1. 创建签名文件
这里写图片描述
2. 填写好签名参数
这里写图片描述
3. 生成APK
注意:签名的密码和密匙的密码注意保管,不要忘了,签名文件别泄漏了,也别搞丢了
为什么要打包
我最开始就有这个疑问,我们的代码不是点了下运行按钮就直接安装到手机上了吗,我们在在项目Project目录的build/outputs/apk目录下可以找到刚刚新鲜生成的app-debug.apk.直接把这个上传给市场不就行了吗。
这里写图片描述
NO,当然不行,想想手机安装App的时候怎么来区分各个APK的。
通过包名+签名 来确定一个应用的唯一性,那个 debug.apk 只是系统用来给我们调试用的,如果上传到市场,怎么来保证他的安全性。
OK,我们已经解决了第一步—怎么打包。上传上去后,市场反馈发现我们的App写得太棒了,这时候老大让赶快多上些平台,主流的平台、非主流的平台都要放上去。
那么问题来了,为了方便统计各个平台的安装情况,配合运营推广,需要统计各个平台的安装情况。
分渠道打包
不错,我们需要用到分渠道打包,那么我们需要解决两个问题
1. 怎么区分各个平台的标识
2. 怎么每次版本更新都生成几十个包、几百个包
第一个简单,用过友盟打包的同学肯定不陌生这段代码
<meta-data android:name="UMENG_CHANNEL" android:value="Channel_ID"></meta-data>
value里面填的就是各个平台的值,比如填写uc、yyb(应用宝)、360、替换掉Channel_ID,App安装好,可以读取这个值然后传给后台,从而实现区分各个平台的安装需求。
第二个问题:
在Eclipse时代,最开始我是手动打的,一次打30个包,每次最怕版本更新,基本一下午都在做机械运动,现在想起来手都在抽筋。
后来,学会了Ant自动打包,快倒是快,只是配置太坑爹了,超级麻烦。
现在有了Android Studio,妈妈再也不用担心我不能愉快的打包了。
随便新建一个项目,修改Mole:app build.gradle为
‘拾’ 如何将h5程序打包成android应用
H5开发的web APP和原生APP的区别有以下几个方面: 一、开发方面 原生App ⊙ 每一种移动操作系统都需要独立的开发项目 ⊙ 每种平台都需要独立的开发语言。Java(Android), Objective-C(iOS)以及VisualC++(Windows Mobile)等等 ⊙ 需要使用各自的软件开发包,开发工具以及各自的控件 移动Web App ⊙ 因为运行在移动设备的浏览器上,所以只需要一个开发项目 ⊙ 这种应用可以使用HTML5,CSS3以及JavaScript以及服务器端语言来完成(PHP,Ruby on Rails,Python) ⊙ 这里可没有标准的SDK,基本任意选择别忘了有一些跨平台的开发工具,比如PhoneGap, Sencha Touch 2,APPcan以及Appcelerator Titanium等等。 二、能力方面 原生App ⊙ 能够与移动硬件设备的底层功能,比如个人信息,摄像头以及重力加速器等等 移动Web App ⊙ 只能使用有限的移动硬件设备功能。 三、获取方法 原生App ⊙ 直接下载到设备 ⊙ 以独立的应用程序运行(并不需要浏览器) ⊙ 用户必须手动去下载并安装这些原生App ⊙ 有一些商店与卖场来帮助用户寻找你的App,目前app市场不计其数 移动Web App ⊙ 从移动设备上的浏览器访问 ⊙ 不需要安装额外的软件 ⊙ 软件更新只需要服务器就够了 ⊙ 因为现在没有什么商品或卖场提供这种App,所以如何搜索这些移动Web App相当不简单。 四、版本控制 原生App ⊙ 用户可以自由地选择是否更新软件版本,所以会出现不同用户同时使用不同版本的情况 移动Web App ⊙ 所有的用户都是用同样的版本 五、优势 原生App ⊙ 比移动Web App运行快 ⊙ 一些商店与卖场会帮助用户寻找原生App ⊙ 官方卖场的应用审核流程会保证让用户得到高质量以及安全的App ⊙ 官方会发布很多开发工具或者人工支持来帮助你的开发 移动Web App ⊙ 跨平台开发 ⊙ 用户不需要去卖场来下载安装App ⊙ 任何时候都可以发布App,因为根本不需要官方卖场的审核 ⊙ 如果你已经有了一个Web App,你可以使用 responsive web design来辅助改进 六、缺陷 原生App ⊙ 开发成本高,尤其是当需要多种移动设备来测试时 ⊙ 因为是不同的开发语言,所以开发,维护成本也高 ⊙ 因为用户使用的App版本不同,所以你维护起来很困难 ⊙ 官方卖场审核流程复杂且慢,会严重影响你的发布进程 移动Web App ⊙ 无法使用很多移动硬件设备的独特功能 ⊙ 要同时支持多种移动设备的浏览器让开发维护的成本也不低 ⊙ 如果用户使用更多的新型浏览器,那问题就更不好处理了 ⊙ 对于用户来说,这种App很难被用户发现 附:原生App 与 移动Web App:您如何选择? 所以在你准备做移动App时,你应该先问问自己以下几个问题: 1. 你的应用是否需要使用某些设备的特殊功能,比如摄像头,摄像头闪光灯或者重力加速器 2. 你的开发预算是多少? 3. 你的应用是否一定需要网络 4. 你的应用的目标硬件设备是所有的移动设备还是仅仅只是一部分而已 5. 你自己已经熟悉的开发语言 6. 这个应用对于性能要求是否苛刻 7. 如何靠这个应用赢利