解析manifest 根标签

来源:互联网 发布:盼盼交友软件靠谱吗 编辑:程序博客网 时间:2024/06/06 09:41

是否真正的去关注过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的文件信息,获取之后,启动系统的程序更新程序。

整个思路清楚之后,我们就可以移植到自己的程序中。

0 0