1. Design idea, use VersionCode to define as version upgrade parameters.
Android provides 2 properties for us to define the version:
<manifest package=""
android:versionCode="1" <!--Integer type, the system does not display to the user-->
android:versionName="1.0"<!--String type, system displays user-->
></manifest>
Google recommends that we use versionCode to increase the version to indicate the version upgrade, whether it is a big or a small change, while versionName is the software version that the user sees, and is used as a display. So we chose VersionCode as the parameter for our defined version upgrade.
2. Project Directory
In order to have practical guidance for real projects or enterprise applications, I simulate an independent project, and the project directory setting is more reasonable and rigorous, rather than just a demo.
Suppose we take Shanghai Metro as the project and name it "Subway", the engineering structure is as follows,
3. Comparison between version initialization and version number.
First, define the variables localVersion and serverVersion in the global file to store the local version number and server version number respectively.
public class Global {
// Version information
public static int localVersion = 0;
public static int serverVersion = 0;
public static String downloadDir = "app/download/";
}
Because this article only focuses on upgrading and updating, in order to prevent too many other irrelevant codes from being redundant, I directly define the method initGlobal() method in SubwayApplication.
/**
* Initialize global variables
* In actual work, serverVersion is obtained from the server side, and it is best to execute it in the activity of the startup screen.
*/
public void initGlobal(){
try{
= getPackageManager().getPackageInfo(getPackageName(),0).versionCode; //Set the local version number
= 1;//Assuming that the server version is 2, the local version is 1 by default
}catch (Exception ex){
();
}
}
If a new version is detected and prompts the user to update, I defined the checkVersion() method in SubwayActivity:
/**
* Check for updated versions
*/
public void checkVersion(){
if( < ){
//Discover a new version and prompt the user to update
alert = new (this);
("Software Upgrade")
.setMessage("New version is found, it is recommended to update and use it immediately.")
.setPositiveButton("Update", new () {
public void onClick(DialogInterface dialog, int which) {
//Open the update service UpdateService
//In order to make update more modular, you can pass some updateService dependency values here
//For example, layout ID, resource ID, dynamically obtained title, here we take app_name as an example
Intent updateIntent =new Intent(, );
("titleId",.app_name);
startService(updateIntent);
}
})
.setNegativeButton("Cancel",new (){
public void onClick(DialogInterface dialog, int which) {
();
}
});
().show();
}else{
//Cleaning work, omit
//cheanUpdateFile(), I will attach the code after the article
}
}
OK, let's string these things now:
The first step is to execute initGlobal() initialization version variable in the onCreate() method of SubwayApplication.
public void onCreate() {
();
initGlobal();
}
The second step is to detect the version update checkVersion() in the onCreate() method of SubwayActivity.
public void onCreate(Bundle savedInstanceState) {
(savedInstanceState);
setContentView();
checkVersion();
Now the entrance has been opened, and it can be seen in the 18th line of the checkVersion method that when the user clicks to update, we enable the update service and download the latest version from the server.
4. Use Service to download from the server in the background, prompt the user to complete the download and close the service after completion.
Define a service, first define variables related to download and notification:
//title
private int titleId = 0;
//File storage
private File updateDir = null;
private File updateFile = null;
//Notification column
private NotificationManager updateNotificationManager = null;
private Notification updateNotification = null;
//Notification bar jumps to Intent
private Intent updateIntent = null;
private PendingIntent updatePendingIntent = null;
Prepare related download work in the onStartCommand() method:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Get the pass value
titleId = ("titleId",0);
//Create a file
if(.MEDIA_MOUNTED.equals(())){
updateDir = new File((),);
updateFile = new File((),getResources().getString(titleId)+".apk");
}
= (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
= new Notification();
// During the download process, click the notification bar and return to the main interface
updateIntent = new Intent(this, );
updatePendingIntent = (this,0,updateIntent,0);
//Set the notification bar to display content
= .arrow_down_float;
= "Start download";
(this,"Shanghai Metro","0%", updatePendingIntent);
//Give a notice
(0,updateNotification);
//Open a new thread download. If you use Service to synchronize the download, it will cause ANR problems and the Service itself will also block.
new Thread(new updateRunnable()).start();//This is the focus of downloading, it is the downloading process
return (intent, flags, startId);
}
All preparations are available
It can be seen from the code that the updateRunnable class is the real downloaded class. For user experience, this class is executed by us in a separate thread background.
The download process has two tasks: 1. Download data from the server; 2. Notify the user of the download progress.
For thread notification, we first define an empty updateHandler.
[/code]
private Handler updateHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
}
};
[/code]
Let's create the real implementation of the updateRunnable class:
class updateRunnable implements Runnable {
Message message = ();
public void run() {
= DOWNLOAD_COMPLETE;
try{
//Add permissions <uses-permission android:name=".WRITE_EXTERNAL_STORAGE">;
if(!()){
();
}
if(!()){
();
}
//Download the function, take QQ as an example
//Add permissions <uses-permission android:name="">;
long downloadSize = downloadUpdateFile("http://softfile.:8080/msoft/179/1105/10753/MobileQQ1.0(Android)_Build0198.apk",updateFile);
if(downloadSize>0){
//Download successfully
(message);
}
}catch(Exception ex){
();
= DOWNLOAD_FAIL;
//Download failed
(message);
}
}
}
</uses-permission></uses-permission>
There are many implementations of download functions. I will post the code here, and we will notify the user of the download progress when downloading:
public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception {
//There are many download codes like this, so I won't explain too much
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;
HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL(downloadUrl);
httpConnection = (HttpURLConnection)();
("User-Agent", "PacificHttpClient");
if(currentSize > 0) {
("RANGE", "bytes=" + currentSize + "-");
}
(10000);
(20000);
updateTotalSize = ();
if (() == 404) {
throw new Exception("fail!");
}
is = ();
fos = new FileOutputStream(saveFile, false);
byte buffer[] = new byte[4096];
int readsize = 0;
while((readsize = (buffer)) > 0){
(buffer, 0, readsize);
totalSize += readsize;
//In order to prevent frequent notifications from causing tightness in the application, the percentage increase by 10 will be notified once
if((downloadCount == 0)||(int) (totalSize*100/updateTotalSize)-10>downloadCount){
downloadCount += 10;
(, "Downloading", (int)totalSize*100/updateTotalSize+"%", updatePendingIntent);
(0, updateNotification);
}
}
} finally {
if(httpConnection != null) {
();
}
if(is != null) {
();
}
if(fos != null) {
();
}
}
return totalSize;
}
After the download is completed, we prompt the user to complete the download and can click to install. Then let’s complete the previous Handler.
First define 2 constants to represent the download status:
//Download Status
private final static int DOWNLOAD_COMPLETE = 0;
private final static int DOWNLOAD_FAIL = 1;
Process the main thread according to the download status:
private Handler updateHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(){
case DOWNLOAD_COMPLETE:
//Click to install PendingIntent
Uri uri = (updateFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW);
(uri, "application/-archive");
updatePendingIntent = (, 0, installIntent, 0);
= Notification.DEFAULT_SOUND;//Ringtone reminder
(, "Shanghai Metro", "Download is completed, click to install.", updatePendingIntent);
(0, updateNotification);
//Stop service
stopService(updateIntent);
case DOWNLOAD_FAIL:
//Download failed
(, "Shanghai Metro", "Download is completed, click to install.", updatePendingIntent);
(0, updateNotification);
default:
stopService(updateIntent);
}
}
};
At this point, the file is downloaded and the progress is notified in the notification bar.
I found that I talked a lot of nonsense, but in fact, I have written so much about a few words back and forth, and I have been talking about it later. I will work hard to streamline the blog posts later.
PS: The code mentioned earlier to attach cheatUpdateFile()
File updateFile = new File(,getResources().getString(.app_name)+".apk");
if(()){
//When it is not needed, clear the previous download file to avoid wasting user space
();
}