android APP实现更新 PHP后台服务器
android APP实现更新 PHP后台服务器
最近自己在做一款APP,需要实现APP版本更新功能,从网上找了许多资料,只找到了关于移动端的实现。经过我的研究,终于实现了比较完整的android APP版本更新功能,在此分享给广大朋友,但是我的ios端还没实现,但是传输是基于的http协议,实现原理应该是大同小异的。接下来进入正文。
PHP后台服务器实现
后台的实现是基于的thinkPHP框架。对于PHP开发框架thinkPHP框架的朋友,只要去官网下载手册,看那么几页,我想你应该就懂了。
接下来直接给出PHP代码实现。
对于这个文件,大家需要修改的便是命名空间。
namespace API\Controller; use Think\Controller;
至于为什么,大家需要了解下PHP的基础知识,和thinkPHP框架的开发流程就可以了,很快的。
<?php
namespace API\Controller;
use Think\Controller;
class ServerController extends Controller {
public function index(){
//$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "寰蒋闆呴粦"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>娆㈣繋浣跨敤 <b>ThinkPHP</b>锛?/p><br/>[ 鎮ㄧ幇鍦ㄨ闂殑鏄疕ome妯″潡鐨処ndex鎺у埗鍣?]</div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8');
echo "hello";
}
function updateInfo(){
$result=array(
'version'=>'1.0',
'description'=>'目前已经更新了卡屏功能',
'url'=>'http://localhost/index.php/API/Server/download'
);
echo json_encode($result);
}
function download(){
$file = "/tmp/test.apk";
$filename = basename($file);//返回路径中的文件名部分。
/*
* header() 函数向客户端发送原始的 HTTP 报头。
* 必须在任何实际的输出被发送之前调用 header() 函数
* */
header("Content-type: application/octet-stream");
//处理中文文件名
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = rawurlencode($filename);
if (preg_match("/MSIE/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
header("Content-Length: ". filesize($file));
/*
* readfile() 函数输出一个文件。
* 该函数读入一个文件并写入到输出缓冲。
* 若成功,则返回从文件中读入的字节数。若失败,则返回 false。
*/
ob_clean();
flush();
readfile($file);
}
}
这里需要解释的是
function updateInfo()
function download(){
new Thread() {
public void run() {
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse response;
try {
response = client.execute(get);
HttpEntity entity = response.getEntity();
int length = (int) entity.getContentLength();
progressDialog.setMax(length);
InputStream is = entity.getContent();
FileOutputStream fileOutputStream = null;
if (is != null) {
File file = new File(
Environment.getExternalStorageDirectory(),
"Test.apk");
fileOutputStream = new FileOutputStream(file);
byte[] buf = new byte[10];
int ch = -1;
int process = 0;
while ((ch = is.read(buf)) != -1) {
fileOutputStream.write(buf, 0, ch);
process += ch;
progressDialog.setProgress(process);
}
}
fileOutputStream.flush();
if (fileOutputStream != null) {
fileOutputStream.close();
}
down();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
而PHP的实现代码是download中的
ob_clean(); flush(); readfile($file);
至于底层的原理是,readfile方法封装了,http文件传输的基本实现,大家可以百度下,以上两段代码配合,一个客户端,一个服务器,就能够实现基于http文件的传输.
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.administrator.dongzhiwuapp.R;
public class SetActivity extends Activity {
private UpdateInfo info;
private ProgressDialog progressDialog;//下载进度条窗口
UpdateInfoService updateInfoService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.update);
Button button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
checkUpdate();
}
});
}
private void checkUpdate(){
new Thread() {
public void run() {
try {
updateInfoService = new UpdateInfoService(SetActivity.this);
info = updateInfoService.getUpDateInfo();
handler1.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
@SuppressLint("HandlerLeak")
private Handler handler1 = new Handler() {
public void handleMessage(Message msg) {
if (updateInfoService.isNeedUpdate()) {
showUpdateDialog();
}
}
};
private void showUpdateDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setTitle("请升级APP版本至" + info.getVersion());
builder.setMessage(info.getDescription());
builder.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
downFile(info.getUrl());
} else {
Toast.makeText(SetActivity.this, "SD卡不可用,请插入SD卡",
Toast.LENGTH_SHORT).show();
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.create().show();
}
//进入下载
void downFile(final String url) {
progressDialog = new ProgressDialog(SetActivity.this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle("正在下载");
progressDialog.setMessage("请稍后...");
progressDialog.setProgress(0);
progressDialog.show();
updateInfoService.downLoadFile(url, progressDialog,handler1);
}
}
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.administrator.dongzhiwuapp.R;
public class SetActivity extends Activity {
private UpdateInfo info;
private ProgressDialog progressDialog;//下载进度条窗口
UpdateInfoService updateInfoService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.update);
Button button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
checkUpdate();
}
});
}
private void checkUpdate(){
new Thread() {
public void run() {
try {
updateInfoService = new UpdateInfoService(SetActivity.this);
info = updateInfoService.getUpDateInfo();
handler1.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
@SuppressLint("HandlerLeak")
private Handler handler1 = new Handler() {
public void handleMessage(Message msg) {
if (updateInfoService.isNeedUpdate()) {
showUpdateDialog();
}
}
};
private void showUpdateDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setTitle("请升级APP版本至" + info.getVersion());
builder.setMessage(info.getDescription());
builder.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
downFile(info.getUrl());
} else {
Toast.makeText(SetActivity.this, "SD卡不可用,请插入SD卡",
Toast.LENGTH_SHORT).show();
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.create().show();
}
//进入下载
void downFile(final String url) {
progressDialog = new ProgressDialog(SetActivity.this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle("正在下载");
progressDialog.setMessage("请稍后...");
progressDialog.setProgress(0);
progressDialog.show();
updateInfoService.downLoadFile(url, progressDialog,handler1);
}
}
/**
* 获取服务器地址
*/
public class GetServerUrl{
static String url="http://";
public static String getUrl() {
return url;
}
}
/*
*
* 版本更新信息类
* 1、获取版本字符串信息
* 2、设置版本字符串信息
* 3、获取版本描述
* 4、设置版本描述
* 5、获取URL地址
* 6、设置URL地址
* */
public class UpdateInfo
{
private String version;
private String description;
private String url;
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
}
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class UpdateInfoService {
ProgressDialog progressDialog;
Handler handler;
Context context;
UpdateInfo updateInfo;
public UpdateInfoService(Context context){
this.context=context;
}
/*
* 获取更新信息
* 版本信息存储在服务器的update.txt文件中
* 更新信息包括:
* 1、版本信息
* 2、最新版本具体描述
* 3、下载地址
*
* */
public UpdateInfo getUpDateInfo() throws Exception {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://localhost/index.php/API/Server/updateInfo");
HttpResponse httpResponse = httpClient.execute(httpGet);
UpdateInfo updateInfo = new UpdateInfo();
if (httpResponse.getStatusLine().getStatusCode() == 200)//请求相应成功
{
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity, "utf-8");
JSONObject jsonObject=new JSONObject(response);
Log.d("dsdsada", "getUpDateInfo: "+response);
updateInfo.setVersion(jsonObject.getString("version"));
updateInfo.setDescription(jsonObject.getString("description"));
updateInfo.setUrl(jsonObject.getString("url"));
this.updateInfo = updateInfo;
return updateInfo;
}
updateInfo.setVersion("");
updateInfo.setDescription("");
updateInfo.setUrl("");
this.updateInfo = updateInfo;
return updateInfo;
}
/*
*判断是否需要更新
*/
public boolean isNeedUpdate(){
String new_version = updateInfo.getVersion();
String now_version="";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
now_version= packageInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
if (new_version.equals(now_version)) {
return false;
} else {
return true;
}
}
/*
*
* 下载文件
* */
public void downLoadFile(final String url,final ProgressDialog pDialog,Handler h){
progressDialog=pDialog;
handler=h;
new Thread() {
public void run() {
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse response;
try {
response = client.execute(get);
HttpEntity entity = response.getEntity();
int length = (int) entity.getContentLength();
progressDialog.setMax(length);
InputStream is = entity.getContent();
FileOutputStream fileOutputStream = null;
if (is != null) {
File file = new File(
Environment.getExternalStorageDirectory(),
"Test.apk");
fileOutputStream = new FileOutputStream(file);
byte[] buf = new byte[10];
int ch = -1;
int process = 0;
while ((ch = is.read(buf)) != -1) {
fileOutputStream.write(buf, 0, ch);
process += ch;
progressDialog.setProgress(process);
}
}
fileOutputStream.flush();
if (fileOutputStream != null) {
fileOutputStream.close();
}
down();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
//下载完毕,退出下载,进入安装APP步骤
void down() {
handler.post(new Runnable() {
public void run() {
progressDialog.cancel();
update();
}
});
}
//安装最新版本APP
void update() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment
.getExternalStorageDirectory(), "Test.apk")),
"application/vnd.android.package-archive");
context.startActivity(intent);
}
}

