解析manifest 根标签
2016-08-12 17:11
781 查看
是否真正的去关注过AndroidManifest.xml,我们很多的时候知道去写但是其他的很多属性,我们没有去关注,接下来我来去详细去讲解这些属性。
sharedUserId,这个属性不常用,主要多个app访问共享,默认情况下,Android给每个APK分配一个唯一的UserID,所以是默认禁止不同APK访问共享数据的。若要共享数据,第一可以采用Share Preference方法,第二种就可以采用sharedUserId了,将不同APK的sharedUserId都设为一样,则这些APK之间就可以互相共享数据了。
sharedUserLabel,一个共享的用户名,它只有在设置了sharedUserId属性的前提下才会有意义。这两个标签如果是一些大的公司,在开发几款app的时候,才有可能去使用到,我们可以暂时忽略。
versionCode,app的版本号,是给设备程序识别版本(升级)用的必须是一个interger值代表app更新过多少次,比如第一版一般为1,之后若要更新版本就设置为2,3等等。
android:versionName:这个是我们常说明的版本号,由三部分组成..,该值是个字符串,可以显示给用户。重点来了,如果你使用的eclipse,这应该是没有问题的(我没有使用eclipse,我使用的是android studio),你写程序,但是在android studio中是获取不到正确的版本信息的。当你在AndroidManifest.xm中设置后,你会一直获取当的版本信息是1.0 和 1,不管你如何去修改,一直都是这个值,为什么呢?android studio修改了这一格式,如果我们想要去修改版本信息,我们需要去在build.gradle中修改
versionCode和versionName才是我们需要控制的版本信息
我们可以看到当前版本这个属性,
2.在程序更新的时候,我们需要去读取当前app的版本,并且去比较最新的版本,如果最新的版本号大,才去更新。
如何去读取版本信息:
两个方法分别获取了versionName和versionCode。
因为需要用到服务端,我这里使用tomcat,直接部署version.xml和测试的apk
1.下载tomcat,并配置好(大家在网上找相关的教程来配置),在你安装的tomcat目录里的webapps下创建一个test文件夹,并创建version.xml文件,文件内容如下:
这个是标准的xml格式,version就是版本信息,相当于程序中的versionName,url就是我们要更新apk的路径,descriptions就是描述更新的详细信息,serverurl就是获取version.xml的详细地址,可以写,可以不写,因为我们会在程序中直接去写。
在test文件中我们还需要一个apk文件,不过这里我们暂时没用,当我们把整个程序写完了,并修改了版本为2之后,才能将apk放入到这里。
启动tomcat
2.服务端写好了,那么我们接下来写客户端。(我使用的是android studio创建的项目)
写main.xml文件
两个TextView就是现实versionName和versionCode信息的,按钮点击进行更新。
在这里需要使用到一个实体类
现在写上加上获取版本信息的两个方法,运行程序,就可以看到效果了,这里会出现1.0 和1。
接下来就要去处理按钮的点击事件,点击按钮之后,程序会有什么操作呢?
1.发送请求,获取到version.xml文件信息,
2.判断是否需要更新,如果需要更新,弹框提示用户,让用户来选择是否执行更新操作。
3,点击更新后,下载apk,并启动android系统中的安装apk程序。
在第一步操作中,发送请求,并且解析获取到的流。
获取到流,并解析,这里使用Sax解析xml文件方式
我们在按钮的点击事件中写如下操作:
解析出流之后,我们就去判断version.xml版本信息是否和我们程序版本信息一致,不一致需要弹出对话框(请求数据,解析数据,放入了新的线程中),在handler中去执行
showUpdateDialog(info.getDescription());
当用户点击了确定更新,我们去下载apk
这个方法中有一个获取file文件的方法,方法如下:
当apk下载完后,就去执行安装程序,在这里, intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);该段代码是程序卸载后,自动打开程序,需要加上。
运行程序,这里暂时不去点击更新按钮,去修改build.gradle中的版本信息,在此运行,并在生成的apk(需要改名),放入test文件下。并将版本信息该回来,运行程序,点击按钮,就达到想要的效果。
这是我的程序下载地址
http://download.csdn.net/detail/core_ice/9605195
写完程序后,回过头来进行总结
1。版本信息,在android studio下,在manifast.xml中配置versionName和versionCode没有效果了,需要在build.gradle下修改,才起作用。
2。上面的代码只是用来理解的,思路才是最重要的,想要去更新程序,需要知道是否有更高版本的apk,我们需要找后台要(发送请求,获取信息,在实际项目中,一般会传给我们json格式的字符串,但不管怎样,都是获取信息),获取到信息后,判断是否需要去更新,需要更新,就弹出对话框,用户点击对话框后,再次请求获取到apk的文件信息,获取之后,启动系统的程序更新程序。
整个思路清楚之后,我们就可以移植到自己的程序中。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="string" android:sharedUserId="string" android:sharedUserLabel="string resource" android:versionCode="integer" android:versionName="string" android:installLocation=["auto" | "internalOnly" | "preferExternal"] > </manifest>
标签解释
这个是AndroidManifest.xml的根目录,我们大多了解了package这个是什么,就是我们的包名,首先我们创建包的时候需要设置为com.company这种形式的包名(约定的),同时一旦我们的程序发布了,就不能再修改该包名了,否则会被认为不是同一程序,以前的用户就无法更新到最新的程序了。sharedUserId,这个属性不常用,主要多个app访问共享,默认情况下,Android给每个APK分配一个唯一的UserID,所以是默认禁止不同APK访问共享数据的。若要共享数据,第一可以采用Share Preference方法,第二种就可以采用sharedUserId了,将不同APK的sharedUserId都设为一样,则这些APK之间就可以互相共享数据了。
sharedUserLabel,一个共享的用户名,它只有在设置了sharedUserId属性的前提下才会有意义。这两个标签如果是一些大的公司,在开发几款app的时候,才有可能去使用到,我们可以暂时忽略。
versionCode,app的版本号,是给设备程序识别版本(升级)用的必须是一个interger值代表app更新过多少次,比如第一版一般为1,之后若要更新版本就设置为2,3等等。
android:versionName:这个是我们常说明的版本号,由三部分组成..,该值是个字符串,可以显示给用户。重点来了,如果你使用的eclipse,这应该是没有问题的(我没有使用eclipse,我使用的是android studio),你写程序,但是在android studio中是获取不到正确的版本信息的。当你在AndroidManifest.xm中设置后,你会一直获取当的版本信息是1.0 和 1,不管你如何去修改,一直都是这个值,为什么呢?android studio修改了这一格式,如果我们想要去修改版本信息,我们需要去在build.gradle中修改
defaultConfig { applicationId "com.ice.testandroidmanifest" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" }
versionCode和versionName才是我们需要控制的版本信息
使用场地
1.这两个属性是更迭版本的时候需要使用到的。我们可以看到当前版本这个属性,
2.在程序更新的时候,我们需要去读取当前app的版本,并且去比较最新的版本,如果最新的版本号大,才去更新。
如何去读取版本信息:
public String getVersion(Context context)//获取版本号 { try { PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return pi.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return null; }
public int getVersionCode(Context context)//获取版本号(内部识别号) { try { PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return pi.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return 0; } }
两个方法分别获取了versionName和versionCode。
测试用例
知道了使用的场合,那么接下来就去使用它,android只要涉及到版本的迭代,那么更新是少不了的,既然这样,就直接写一个程序来完成它,接下来,我就来讲解如何去完成这个测试的程序的。因为需要用到服务端,我这里使用tomcat,直接部署version.xml和测试的apk
1.下载tomcat,并配置好(大家在网上找相关的教程来配置),在你安装的tomcat目录里的webapps下创建一个test文件夹,并创建version.xml文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?> <info> <version>2.0</version> <url>http://192.168.31.53:8080/test/TestAndroidManifest.apk</url> <descriptions>down and update</descriptions> <serverurl>http://192.168.31.53:8080/test/version.xml</serverurl> </info>
这个是标准的xml格式,version就是版本信息,相当于程序中的versionName,url就是我们要更新apk的路径,descriptions就是描述更新的详细信息,serverurl就是获取version.xml的详细地址,可以写,可以不写,因为我们会在程序中直接去写。
在test文件中我们还需要一个apk文件,不过这里我们暂时没用,当我们把整个程序写完了,并修改了版本为2之后,才能将apk放入到这里。
启动tomcat
2.服务端写好了,那么我们接下来写客户端。(我使用的是android studio创建的项目)
写main.xml文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.ice.testandroidmanifest.MainActivity"> <TextView android:id="@+id/version" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:textSize="24sp"/> <TextView android:id="@+id/versioncode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/version" android:layout_marginTop="24dp" android:text="Hello World!" android:textSize="24sp"/> <Button android:id="@+id/update_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="点击更新" android:textSize="24sp" android:layout_centerInParent="true"/> </RelativeLayout>
两个TextView就是现实versionName和versionCode信息的,按钮点击进行更新。
在这里需要使用到一个实体类
public class UpdateInfo { private String version; //版本信息 private String url; //apk地址 private String description; //详细描述信息 private String url_server; //服务器版本信息路径 public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getUrl_server() { return url_server; } public void setUrl_server(String url_server) { this.url_server = url_server; } }
现在写上加上获取版本信息的两个方法,运行程序,就可以看到效果了,这里会出现1.0 和1。
接下来就要去处理按钮的点击事件,点击按钮之后,程序会有什么操作呢?
1.发送请求,获取到version.xml文件信息,
2.判断是否需要更新,如果需要更新,弹框提示用户,让用户来选择是否执行更新操作。
3,点击更新后,下载apk,并启动android系统中的安装apk程序。
在第一步操作中,发送请求,并且解析获取到的流。
public InputStream getInputStream() { InputStream is = null; String path = getResources().getString(R.string.url_server); try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { //获取成功 is = conn.getInputStream(); } } catch (Exception e) { e.printStackTrace(); } return is; }
获取到流,并解析,这里使用Sax解析xml文件方式
public class UpdateInfoHandler extends DefaultHandler{ List<UpdateInfo> mUpdateInfos; UpdateInfo mUpdateInfo; String elementTag=null; public static UpdateInfo getUpdateInfos(InputStream is){ SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); UpdateInfoHandler handler = new UpdateInfoHandler(); try { parser.parse(is, handler); } catch (IOException e) { e.printStackTrace(); } List<UpdateInfo> updateInfos = handler.getUpdateInfos(); return updateInfos.get(0); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } return null; } public List<UpdateInfo> getUpdateInfos() { return mUpdateInfos; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (elementTag != null){ String data = new String(ch,start, length).trim(); if ("version".equals(elementTag)) { mUpdateInfo.setVersion(data); } else if ("url".equals(elementTag)) { mUpdateInfo.setUrl(data); } else if ("descriptions".equals(elementTag)) { mUpdateInfo.setDescription(data); } else if ("serverurl".equals(elementTag)) { mUpdateInfo.setUrl_server(data); } } } @Override public void startDocument() throws SAXException { mUpdateInfos = new ArrayList<>(); } @Override public void endDocument() throws SAXException { super.endDocument(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("info".equals(localName)){ mUpdateInfo = new UpdateInfo(); } elementTag = localName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("info".equals(localName) && mUpdateInfo != null){ mUpdateInfos.add(mUpdateInfo); mUpdateInfo = null; } elementTag = null; } }
我们在按钮的点击事件中写如下操作:
new Thread(new Runnable() { @Override public void run() { //发送请求获取版本信息 InputStream inputStream = getInputStream(); Message message = new Message(); try { info = UpdateInfoHandler.getUpdateInfos(inputStream); if (info != null) { //获取信息成功 if (info.getVersion().equals(getVersion(MainActivity.this))) { System.out.println("版本一致"); message.what = UPDATA_NONEED; } else { System.out.println("版本不一致"); message.what = UPDATA_CLIENT; } mHandler.sendMessage(message); } else { //获取信息失败 message.what = GET_UNDATAINFO_ERROR; mHandler.sendMessage(message); } } catch (Exception e) { message.what = GET_UNDATAINFO_ERROR; mHandler.sendMessage(message); e.printStackTrace(); } } }).start();
解析出流之后,我们就去判断version.xml版本信息是否和我们程序版本信息一致,不一致需要弹出对话框(请求数据,解析数据,放入了新的线程中),在handler中去执行
showUpdateDialog(info.getDescription());
private void showUpdateDialog(String messageInfo) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("版本升级"); builder.setMessage(messageInfo); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //下载apk downLoadApk(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取消弹框 } }); AlertDialog dialog = builder.create(); dialog.show(); }
当用户点击了确定更新,我们去下载apk
private void downLoadApk() { final ProgressDialog pd; //进度条框 pd = new ProgressDialog(this); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage("正在下载更新"); pd.show(); new Thread() { @Override public void run() { try { File file = DownLoadManager.getFileFromServer(info.getUrl(), pd); sleep(3000); installApk(file); pd.dismiss(); //结束掉进度条框 } catch (Exception e) { Message msg = new Message(); msg.what = DOWN_ERROR; mHandler.sendMessage(msg); e.printStackTrace(); } } }.start(); }
这个方法中有一个获取file文件的方法,方法如下:
public static File getFileFromServer(String path, ProgressDialog pd) throws Exception { //相等表示前sdcard挂载手机并且用 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); //获取文件 pd.setMax(conn.getContentLength()); InputStream is = conn.getInputStream(); File file = new File(Environment.getExternalStorageDirectory(), "TestAndroidManifest.apk"); FileOutputStream fos = new FileOutputStream(file); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer = new byte[1024]; int len; int total = 0; while ((len = bis.read(buffer)) != -1) { fos.write(buffer, 0, len); total += len; //获取前载量 pd.setProgress(total); } fos.close(); bis.close(); is.close(); return file; } else { return null; } }
当apk下载完后,就去执行安装程序,在这里, intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);该段代码是程序卸载后,自动打开程序,需要加上。
private void installApk(File file) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); startActivity(intent); }
运行程序,这里暂时不去点击更新按钮,去修改build.gradle中的版本信息,在此运行,并在生成的apk(需要改名),放入test文件下。并将版本信息该回来,运行程序,点击按钮,就达到想要的效果。
这是我的程序下载地址
http://download.csdn.net/detail/core_ice/9605195
写完程序后,回过头来进行总结
1。版本信息,在android studio下,在manifast.xml中配置versionName和versionCode没有效果了,需要在build.gradle下修改,才起作用。
2。上面的代码只是用来理解的,思路才是最重要的,想要去更新程序,需要知道是否有更高版本的apk,我们需要找后台要(发送请求,获取信息,在实际项目中,一般会传给我们json格式的字符串,但不管怎样,都是获取信息),获取到信息后,判断是否需要去更新,需要更新,就弹出对话框,用户点击对话框后,再次请求获取到apk的文件信息,获取之后,启动系统的程序更新程序。
整个思路清楚之后,我们就可以移植到自己的程序中。
相关文章推荐
- java 解析SOAP字符串指定标签转换为实体类
- Spring4.3.x 浅析xml配置的解析过程(11)——解析aop命名空间之scoped-proxy标签
- Android manifest文件中的标签介绍
- AndroidManifest.xml文件解析
- AndroidManifest.xml文件解析
- 浅谈iOS解析HTMl标签以及开发中的一些坑
- poi读取Excel时日期为数字 的解决方法 转载 2017年12月14日 10:31:14 标签:poi /excel /java 19 在使用poi解析Excel文件时,会发现,表格中的日期解析出
- Cordova页面解析页面中script标签内容失败,Refused to execute inline script because it violates the following
- 利用a标签自动解析URL分析网址实例
- 解析Html生成标签树(前言)
- <script>标签的加载解析执行
- maven的pom.xml配置文件中常用的配置标签解析
- androidmanifest.xml高级属性解析
- <space>标签解析 thinksns
- Ajax 上传文件返回JSON字符串FireFox解析出来后带有<pre>标签解决办法
- Android从零开始-AndroidManifest.xml解析
- AndroidManifest.xml 资料解析
- ANDROID的MANIFEST.XML文件字段解析
- 不修改客户端 实现"单标签名称"解析
- 从零开始前端学习[46]:在标签中添加内容,关于innerHTML和innerText的一点解析