在Android項目中,經常需要檢測新版本,然後詢問用戶是否需要更新
爲了方便代碼複用,我把大部分代碼放到一個類裏,大概思路是,先從服務器獲取版本信息,再與當前版本信息進行比較,若有新版本,彈出對話框詢問是否更新,若更新就進行下載,下完後啓動安裝
主要用到HttpURLConnection,jsonObject,PackageManager,File,FileProvider等內容
1.MainActivity.java
這裏主要調用封裝好的類,但是一定要完成權限檢測,讀寫權限需要用戶授權。關於運行時權限的請求可以參考之前的文章
【Android】Android 6.0 獲取危險權限、運行時權限、一次申請多個權限
public class MainActivity extends AppCompatActivity {
private boolean isCanWrite=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission_single();//請求授權
//檢查更新
CheckUpdate checkUpdate = new CheckUpdate(this,isCanWrite);
checkUpdate.checkUpdate();
private void requestPermission_single(){
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}else{
Log.e("請求權限", "requestPermission_single: 已經獲得讀寫權限" );
isCanWrite = true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Toast.makeText(getApplicationContext(),"已獲取讀寫權限!!",Toast.LENGTH_SHORT).show();
isCanWrite = true;
CheckUpdate checkUpdate = new CheckUpdate(this,isCanWrite);
checkUpdate.checkUpdate();
}else {
Toast.makeText(getApplicationContext(),"您拒絕了讀寫權限!!",Toast.LENGTH_SHORT).show();
}
}
}
2.CheckUpdate.java
public class CheckUpdate extends AppCompatActivity {
private Context context;//上下文對象
private String version,whatisnew,downloadurl;//從服務器獲取的版本、說明、下載鏈接等信息
private ProgressBar mProgressBar;//下載進度條
private int mProgress;//下載的進度
private boolean isCancel = false;//取消下載
private boolean isCanWrite; //是否擁有讀寫權限
private String savePath;//存儲路徑
private Dialog downloadDialog;//顯示下載的對話框
public CheckUpdate(Context context,boolean isCanWrite){
this.context = context;
this.isCanWrite = isCanWrite;
}
public void checkUpdate(){
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("http://XXXXXXX.php");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line=reader.readLine()) != null){
response.append(line);
}
dealUpdateInfo(response.toString());
}catch (Exception e){e.printStackTrace();}
finally {
if(reader != null){
try{reader.close();}catch (Exception e){e.printStackTrace();}
}
if(connection != null){
connection.disconnect();
}
}
}
}).start();
}
private void dealUpdateInfo(final String response){
//獲取當前版本信息
runOnUiThread(new Runnable() {
@Override
public void run() {
String version_json = response;
try{
//解析從服務器獲取到的json數據,根據自己服務器返回數據的實際情況進行解析
JSONObject jsonObject = new JSONObject(version_json);
version = jsonObject.getString("version");
whatisnew = jsonObject.getString("whatisnew");
downloadurl = jsonObject.getString("downloadurl");
String currentVersion = packageName(context);
//比較版本,看是否有新版本
if(Float.parseFloat(version)>Float.parseFloat(currentVersion)){
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("檢測到新版本");
dialog.setMessage(whatisnew);
dialog.setCancelable(true);
dialog.setPositiveButton("下載", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if(!isCanWrite){
Toast.makeText(context,"請先賦予存儲權限!!",Toast.LENGTH_SHORT).show();
}else{
showDownloadDialog();
Toast.makeText(context,"已經獲得權限!!",Toast.LENGTH_SHORT).show();
}
}
});
dialog.show();
}else {
Toast.makeText(context,"當前是最新版本",Toast.LENGTH_SHORT).show();
}
}catch (Exception e){e.printStackTrace();}
}
});
}
//獲取包名(版本名)
public static String packageName(Context context) {
PackageManager manager = context.getPackageManager();
String name = null;
try {
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
name = info.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return name;
}
//顯示下載進度條
private void showDownloadDialog(){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("下載中");
View view = LayoutInflater.from(context).inflate(R.layout.dialog_progress,null);
mProgressBar = view.findViewById(R.id.id_progress);
builder.setView(view);
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
isCancel = true;
}
});
downloadDialog = builder.create();
downloadDialog.show();
downloadAPK();
}
//下載文件
private void downloadAPK() {
new Thread(new Runnable() {
@Override
public void run() {
try{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
String sdPath = Environment.getExternalStorageDirectory() + "/";
//文件保存路徑
savePath = sdPath + "ice_aFewWord";
File dir = new File(savePath);
if (!dir.exists()){
dir.mkdir();
}
// 開始下載文件
HttpURLConnection conn = (HttpURLConnection) new URL(downloadurl).openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int length = conn.getContentLength();
File apkFile = new File(savePath, version);
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
byte[] buffer = new byte[1024];
while (!isCancel){
int readData = is.read(buffer);
count += readData;
// 計算當前的下載進度
mProgress = (int) (((float)count/length) * 100);
// 更新進度條
updateProgressHandler.sendEmptyMessage(1);
// 下載完成
if (readData < 0){
updateProgressHandler.sendEmptyMessage(2);
break;
}
fos.write(buffer, 0, readData);
}
fos.close();
is.close();
conn.disconnect();
}
}catch(Exception e){
Log.e("下載錯誤", "run: "+e.toString() );
}
}
}).start();
}
private Handler updateProgressHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
mProgressBar.setProgress(mProgress);
break;
case 2:
downloadDialog.dismiss();
installAPK();
}
}
};
//安裝下載好的apk文件
private void installAPK(){
File apkFile = new File(savePath,version);
if(apkFile.exists()){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri;
//若SDK版本大於等24,需要FileProvider纔行,否則報錯
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//記得修改com.xxx.fileprovider與androidmanifest相同
uri = FileProvider.getUriForFile(context,"com.ice.ice_aFewWord.fileprovider",apkFile);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
}else{
uri = Uri.parse("file://" + apkFile.toString());
}
intent.setDataAndType(uri, "application/vnd.android.package-archive");
context.startActivity(intent);
}
}
}
注意:上面的代碼使用到了FileProvider,需要在res文件夾新建xml,以及在AndroidManifest中進行配置,詳情可參考之前的文章
Android】解決Android 7.0及以上版本文件暴露異常exposed beyond app through Intent.getData()的方法