热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

检测应用是否安装和检测版本更新,反之提供下载地址并安装应用(V1.2)

之前写过类似的博客,参见http:blog.csdn.netluzhenyuxfcyarticledetails43986297,现在这个版本添加些功能并优化代码结构。首先我们理

之前写过类似的博客,参见http://blog.csdn.net/luzhenyuxfcy/article/details/43986297,现在这个版本添加些功能并优化代码结构。

首先我们理一下思路:(参见下图)

思路脑图

思路图

1.新建一个工具类用于交互和一些固定的方法 BaseHelper

package com.lzy.demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;

/**
* @author luzhenyu
* @describe


* 工具类
*


*


*/
public class BaseHelper {

/**
* 流转字符串方法
*
* @param is
* @return
*/
public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}

/**
* @describe


* 显示dialog
*


*


*
* @param context
* 环境
* @param strTitle
* 标题
* @param strText
* 内容
* @param icon
* 图标
*/
public static void showDialog(Activity context, String strTitle,
String strText, int icon) {
AlertDialog.Builder tDialog = new AlertDialog.Builder(context);
tDialog.setIcon(icon);
tDialog.setTitle(strTitle);
tDialog.setMessage(strText);
tDialog.setPositiveButton("取消", null);
tDialog.show();
}

/**
* @describe


* 获取权限
*


*


*
* @param permission
* 权限
* @param path
* 路径
*/
public static void chmod(String permission, String path) {
try {
String command = "chmod " + permission + " " + path;
Runtime runtime = Runtime.getRuntime();
runtime.exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}

//
// show the progress bar.
/**
* @describe


* 显示进度条
*


*


*
* @param context
* 环境
* @param title
* 标题
* @param message
* 信息
* @param indeterminate
* 确定性
* @param cancelable
* 可撤销
* @return
*/
public static ProgressDialog showProgress(Context context,
CharSequence title, CharSequence message, boolean indeterminate,
boolean cancelable) {
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setIndeterminate(indeterminate);
dialog.setCancelable(false);
dialog.setOnCancelListener(new OnCancelListener() {

@Override
public void onCancel(DialogInterface dialog) {

}
});

dialog.show();
return dialog;
}

/**
* @describe


* 字符串转json对象
*


*


* @param str
* @param split
* @return
*/
public static JSONObject string2JSON(String str, String split) {
JSONObject json = new JSONObject();
try {
String[] arrStr = str.split(split);
for (int i = 0; i String[] arrKeyValue = arrStr[i].split("=");
json.put(arrKeyValue[0],
arrStr[i].substring(arrKeyValue[0].length() + 1));
}
}

catch (Exception e) {
e.printStackTrace();
}

return json;
}
}

2.网络交互类 NetworkManager

package com.lzy.demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

/**
* @author luzhenyu
* @describe


* 网络连接工具类
*


*


*/
public class NetworkManager {
static final String TAG = "NetworkManager";

private int cOnnectTimeout= 30 * 1000;
private int readTimeout = 30 * 1000;
Proxy mProxy = null;
Context mContext;

public NetworkManager(Context context) {
this.mCOntext= context;
setDefaultHostnameVerifier();
}

/**
* @describe


* 检查代理,是否cnwap接入
*


*


*/
private void detectProxy() {
ConnectivityManager cm = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni != null && ni.isAvailable()
&& ni.getType() == ConnectivityManager.TYPE_MOBILE) {
@SuppressWarnings("deprecation")
String proxyHost = android.net.Proxy.getDefaultHost();
@SuppressWarnings("deprecation")
int port = android.net.Proxy.getDefaultPort();
if (proxyHost != null) {
final InetSocketAddress sa = new InetSocketAddress(proxyHost,
port);
mProxy = new Proxy(Proxy.Type.HTTP, sa);
}
}
}

private void setDefaultHostnameVerifier() {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};

HttpsURLConnection.setDefaultHostnameVerifier(hv);
}

/**
* @describe


* 发送和接收数据
*


*


*
* @param strReqData
* 请求数据
* @param strUrl
* 请求地址
* @return
*/
public String SendAndWaitResponse(String strReqData, String strUrl) {
detectProxy();

String strRespOnse= null;
ArrayList pairs = new ArrayList();
pairs.add(new BasicNameValuePair("requestData", strReqData));

HttpURLConnection httpCOnnect= null;
UrlEncodedFormEntity p_entity;
try {
p_entity = new UrlEncodedFormEntity(pairs, "utf-8");
URL url = new URL(strUrl);

if (mProxy != null) {
httpCOnnect= (HttpURLConnection) url.openConnection(mProxy);
} else {
httpCOnnect= (HttpURLConnection) url.openConnection();
}
httpConnect.setConnectTimeout(connectTimeout);
httpConnect.setReadTimeout(readTimeout);
httpConnect.setDoOutput(true);
httpConnect.addRequestProperty("Content-type",
"application/x-www-form-urlencoded;charset=utf-8");

httpConnect.connect();

OutputStream os = httpConnect.getOutputStream();
p_entity.writeTo(os);
os.flush();

InputStream cOntent= httpConnect.getInputStream();
strRespOnse= BaseHelper.convertStreamToString(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
httpConnect.disconnect();
}

return strResponse;
}

/**
* @describe


* 下载文件
*


*


*
* @param context
* 上下文环境
* @param strurl
* 下载地址
* @param path
* 下载路径
* @return
*/
public boolean urlDownloadToFile(Context context, String strurl, String path) {
boolean bRet = false;

detectProxy();

try {
URL url = new URL(strurl);
HttpURLConnection cOnn= null;
if (mProxy != null) {
cOnn= (HttpURLConnection) url.openConnection(mProxy);
} else {
cOnn= (HttpURLConnection) url.openConnection();
}
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
conn.setDoInput(true);

conn.connect();
InputStream is = conn.getInputStream();

File file = new File(path);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);

byte[] temp = new byte[1024];
int i = 0;
while ((i = is.read(temp)) > 0) {
fos.write(temp, 0, i);
}

fos.close();
is.close();

bRet = true;

} catch (IOException e) {
e.printStackTrace();
}

return bRet;
}
}


3.对外调用方法汇合类  里面都设置了public访问权限,可以单独调用也可以使用混合调用,里面有些方法还是挺实用的


package com.lzy.demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;

/**
* @author luzhenyu
* @version 1.0
* @describe


* 检测工具类
*


*


* */
public class DetectHelper {
@SuppressWarnings("unused")
private static final String TAG = "DetectHelper";

private ProgressDialog mProgress = null;
private Context mCOntext= null;

public DetectHelper() {

}

public DetectHelper(Context mContext) {
this.mCOntext= mContext;
}

/**
* @describe


* 检测手机是否安装,如果没有则先从assets文件下安装/网络上下载安装,并检测是否需要更新,汇总调用方法
*


*


* */
public void detectMobile() {
if (detectIsInstall(Constant.PACKAGENAME_STRING)) {// "com.lzy.appdemo"
// 采用文件或者一个静态类来管理
// 根据需要进行处理
startApplicationByPackageName(Constant.PACKAGENAME_STRING);
} else {
inStallAppFromAssets(Constant.APKNAME_STRING);
// 检测版本更新
// 对话框
mProgress = BaseHelper
.showProgress(mContext, null, "正在检测更新", false, true);
// 子线程进行检查更新耗时操作
new Thread(new Runnable() {

@Override
public void run() {
checkUpdate();
}

}).start();
}

}

public void checkUpdate() {
// 获取系统缓存目录
File cacheDir = mContext.getCacheDir();
final String cachePath = cacheDir.getAbsolutePath() + "/temp.apk";
// 检测是否有新的版本。
PackageInfo apkInfo = getApkInfo(mContext, cachePath);
String newApkdlUrl = checkNewUpdate(apkInfo);

//
// 动态下载
if (newApkdlUrl != null)
retrieveApkFromNet(mContext, newApkdlUrl, cachePath);

// 发送结果
Message msg = new Message();
msg.what = Constant.INSTALL_CHECK;
msg.obj = cachePath;
mHandler.sendMessage(msg);

}

/**
* @describe


* 从assets目录捆绑安装APP
*


*


* @param apkName
* - String
* @return true if assets file exist you need apk,or false
* */
public boolean inStallAppFromAssets(String apkName) {
boolean exist = false;
// 获取系统缓存目录
File cacheDir = mContext.getCacheDir();
final String cachePath = cacheDir.getAbsolutePath() + "/temp.apk";
try {
InputStream inputStream = mContext.getAssets().open(apkName);
File file = new File(cachePath);
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);

byte[] temp = new byte[1024];
int i = 0;
while ((i = inputStream.read(temp)) > 0) {
fileOutputStream.write(temp, 0, i);
}

fileOutputStream.close();
inputStream.close();

exist = true;
} catch (Exception e) {
exist = false;
}
return exist;
}

/**
* @describe


* 根据报名启动应用程序
*


*


* @param packageName
* - String
* */
public void startApplicationByPackageName(String packageName) {
PackageManager packageManager = mContext.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(packageName);
mContext.startActivity(intent);
}

/**
* @describe


* 检测手机是否安装xxxxAPP
*


*


* @param packageName
* - String
* @return ture if install,or false
* */
public boolean detectIsInstall(String packageName) {
boolean isInstall = false;
PackageManager mPackageManager = mContext.getPackageManager();
List packageInfos = mPackageManager
.getInstalledPackages(0);
for (int i = 0, len = packageInfos.size(); i PackageInfo info = packageInfos.get(i);
if (info.packageName.equalsIgnoreCase(packageName)) {
isInstall = true;
} else {
isInstall = false;
}
}
return isInstall;
}

/**
* @describe

获取未安装的APK信息


* @param context
* @param archiveFilePath
* APK文件的路径。如:/sdcard/download/XX.apk
*/
public static PackageInfo getApkInfo(Context context, String archiveFilePath) {
PackageManager pm = context.getPackageManager();
PackageInfo apkInfo = pm.getPackageArchiveInfo(archiveFilePath,
PackageManager.GET_META_DATA);
return apkInfo;
}

/**
* @describe

检查是否有新版本,如果有,返回apk下载地址


* @param packageInfo
* {@link PackageInfo}
* @return
*/
public String checkNewUpdate(PackageInfo packageInfo) {
String url = null;

try {
JSONObject resp = sendCheckNewUpdate(packageInfo.versionName);
if (resp.getString("needUpdate").equalsIgnoreCase("true")) {
url = resp.getString("updateUrl");
}
} catch (Exception e) {
e.printStackTrace();
}

return url;
}

/**
* @describe

发送当前版本信息,返回是否需要升级 如果需要升级返回更新apk地址


* @param versionName
* 当前版本号
* @return
*/
public JSONObject sendCheckNewUpdate(String versionName) {
JSONObject objResp = null;
try {
JSONObject req = new JSONObject();
req.put(Constant.ACTION, Constant.ACTIONUPDATE);

JSONObject data = new JSONObject();
data.put(Constant.PLATFORM, "android");
data.put(Constant.VERSION, versionName);
data.put(Constant.PARTENER, "");

req.put(Constant.DATA, data);

objResp = sendRequest(req.toString());
} catch (JSONException e) {
e.printStackTrace();
}

return objResp;
}

/**
* @describe

发送json数据


* @param content
* @return
*/
public JSONObject sendRequest(final String content) {
NetworkManager nM = new NetworkManager(this.mContext);

JSONObject jsOnResponse= null;
try {
String respOnse= null;

synchronized (nM) {
respOnse= nM.SendAndWaitResponse(content, Constant.SERVER_STRING);
}

jsOnResponse= new JSONObject(response);
} catch (Exception e) {
e.printStackTrace();
}

return jsonResponse;
}

/**
* @describe

从网络上动态下载apk


* @param context
* 上下文环境
* @param strurl
* 下载地址
* @param filename
* 文件名称
* @return
*/
public boolean retrieveApkFromNet(Context context, String strurl,
String filename) {
boolean bRet = false;

try {
NetworkManager nM = new NetworkManager(this.mContext);
bRet = nM.urlDownloadToFile(context, strurl, filename);
} catch (Exception e) {
e.printStackTrace();
}

return bRet;
}

//
// close the progress bar
public void closeProgress() {
try {
if (mProgress != null) {
mProgress.dismiss();
mProgress = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}

@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
try {
switch (msg.what) {
case Constant.INSTALL_CHECK: {
closeProgress();
String cachePath = (String) msg.obj;
showInstallConfirmDialog(mContext, cachePath);
}
break;
}

super.handleMessage(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
};

/**
* @describe

显示确认安装的提示


* @param context
* 上下文环境
* @param cachePath
* 安装文件路径
*/
public void showInstallConfirmDialog(final Context context,
final String cachePath) {
AlertDialog.Builder tDialog = new AlertDialog.Builder(context);
tDialog.setIcon(R.drawable.ic_launcher);
tDialog.setTitle("安装提示");
tDialog.setMessage("您还没有安装XXXX。\n\n点击确定,立即安装。");

tDialog.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//
// 修改apk权限
BaseHelper.chmod("777", cachePath);

//
// install the apk.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + cachePath),
"application/vnd.android.package-archive");
context.startActivity(intent);
}
});

tDialog.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});

tDialog.show();
}

}

4.为了便于管理一些常用的静态字段和上传服务器参数字段,采用一个静态类Constant 实现,对于以后的更新维护更方便。

package com.lzy.demo;

/**
* @author luzhenyu
* @describe

静态字段


* */
public class Constant
{
public final static int INSTALL_CHECK = 0x123;

//参数根据实际开发的需求定义和传递,这里采用的是阿里巴巴的
public final static String ACTION = "action";
public final static String ACTIOnUPDATE= "update";
public final static String DATA = "data";
public final static String PLATFORM = "platform";
public final static String VERSION = "version";
public final static String PARTENER = "partner";

public final static String APKNAME_STRING = "TransActionBarDemo.apk";//assets文件夹下apk名称
public final static String PACKAGENAME_STRING = "com.lzy.appdemo";//要安装的APP的包名
public final static String SERVER_STRING = "https://msp.alipay.com/x.htm";//获取更新服务器地址
}

5.最后别忘了在AndroidManifest.xml中添加权限





        至此整个可以复用的功能完成了,当然,在具体的开发中可能会有不同,比如网络访问这块可能采用的第三方框架,基本思路就是这样,在开发中改动一下接口的访问方式和参数就可以转化为你的功能,这里使用的是阿里巴巴的接口,非常感谢阿里巴巴。

看到了一篇采用Xml方式更新的博客,在此也贴出飞机票:http://blog.csdn.net/furongkang/article/details/6886526

再次说明,实际开发中请根据需要,改动这几个文件的某些实现方法。

方便大家也是方便自己,分享让世界更美好。— — love hy.

【欢迎上码】

【微信公众号搜索 h2o2s2】



推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • importjava.util.ArrayList;publicclassPageIndex{privateintpageSize;每页要显示的行privateintpageNum ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
author-avatar
某一句爱的搁浅-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有