热门标签 | 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官方文档进行了适当修改,旨在介绍如何实现一个能够同时处理多个客户端请求的服务端程序。在前文中,我们探讨了单客户端访问的服务端实现,而本篇将深入讲解多客户端环境下的服务端设计与实现。 ... [详细]
  • 1、编写一个Java程序在屏幕上输出“你好!”。programmenameHelloworld.javapublicclassHelloworld{publicst ... [详细]
  • 本文探讨了如何在 Spring MVC 框架下,通过自定义注解和拦截器机制来实现细粒度的权限管理功能。 ... [详细]
  • JUnit下的测试和suite
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • Java多线程售票案例分析
    本文通过一个售票系统的实例,深入探讨了Java中的多线程技术及其在资源共享和并发控制中的应用。售票过程涉及查询、收款、找零和出票等多个步骤,其中对总票数的管理尤为关键。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • Python3爬虫入门:pyspider的基本使用[python爬虫入门]
    Python学习网有大量免费的Python入门教程,欢迎大家来学习。本文主要通过爬取去哪儿网的旅游攻略来给大家介绍pyspid ... [详细]
  • 探讨了在HTML表单中使用元素代替进行表单提交的方法。 ... [详细]
  • Android 中的布局方式之线性布局
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 函子(Functor)是函数式编程中的一个重要概念,它不仅是一个特殊的容器,还提供了一种优雅的方式来处理值和函数。本文将详细介绍函子的基本概念及其在函数式编程中的应用,包括如何通过函子控制副作用、处理异常以及进行异步操作。 ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 一、Advice执行顺序二、Advice在同一个Aspect中三、Advice在不同的Aspect中一、Advice执行顺序如果多个Advice和同一个JointPoint连接& ... [详细]
  • 使用TabActivity实现Android顶部选项卡功能
    本文介绍如何通过继承TabActivity来创建Android应用中的顶部选项卡。通过简单的步骤,您可以轻松地添加多个选项卡,并实现基本的界面切换功能。 ... [详细]
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社区 版权所有