您的位置:首页 > Web前端

解析manifest 根标签

2016-08-12 17:11 781 查看
是否真正的去关注过AndroidManifest.xml,我们很多的时候知道去写但是其他的很多属性,我们没有去关注,接下来我来去详细去讲解这些属性。

<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的文件信息,获取之后,启动系统的程序更新程序。

整个思路清楚之后,我们就可以移植到自己的程序中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  自动跟新 android