Recently I've started to develop a few Android applications with some friends, and as soon as I started to make updates I faced a problem: how can I tell my beta testers to update to the latest test version?
So I wrote UpdateChecker. It doesn't use the market, just a publicly accessible text file for version check.
For more details you can check it here: http://blog.fdev.eu/updatechecker/
/** This is all you ned to be up and running **/
String VERSION_URL = "http://www.fdev.eu/sample_version.txt";
String REMOTE_APK_URL = "http://www.fdev.eu/sample.apk";
int ALERT_ICON = R.drawable.icon;
UpdateChecker uc = new UpdateChecker(this, VERSION_URL, REMOTE_APK_URL, ALERT_ICON);
uc.startUpdateChecker();
/** The class **/
/**
* Version 1.0 - For latest version check here: http://blog.fdev.eu/updatechecker/
* @author Francesco Capano
*/
public class UpdateChecker {
private String versionUrl;
private String remoteApkUrl;
private int alertIcon;
private final String TAG_SUFFIX = "UpdateChecker";
private String TAG = TAG_SUFFIX;
// The name of the saved file
public String localApkName = "file.apk";
//The dialog that thells you to update
public String alertTitle = "Update now";
public String alertMessage = "Download file and install";
//The dialog which notifies there was an error checking for updates
public String alertTitleError = "Download error";
public String alertMessageError = "There was an error downloading the file";
//Download progress text
public String progressMessage = "Downloading file...";
private Handler mHandler;
private Context context;
private Activity activity;
private AlertDialog alertUpdate, alertError;
private boolean enabled = true;
/* This Thread checks for Updates in the Background */
private Thread checkUpdate;
/**
* Instantiates the update checker
* @param c The activity to be used for displaying the messages
* @param versionUrl The url of the file containing the version name
* @param remoteApkUrl The url of the apk
* @param alertIcon The icon to show in the dialog, usually the application icon
*/
public UpdateChecker(Activity c, String versionUrl, String remoteApkUrl, int alertIcon) {
this.activity = c;
this.context = c.getApplicationContext();
this.versionUrl = versionUrl;
this.remoteApkUrl = remoteApkUrl;
this.alertIcon = alertIcon;
mHandler = new Handler();
}
/**
* Starts to check for updates
*/
public void startUpdateChecker() {
if(!enabled)
return;
if(checkUpdate==null || !checkUpdate.isAlive() || checkUpdate.isInterrupted()) {
checkUpdate = new Thread() {
public void run() {
checkupdate();
}
};
checkUpdate.start();
}
}
/**
* Interrupts update check
*/
public void stopUpdateChecker() {
if(!enabled)
return;
if(checkUpdate.isAlive() && !checkUpdate.isInterrupted())
try {
checkUpdate.interrupt();
} catch(Exception e) {
Log.w(TAG, "checkUpdate.interrupt() exception");
// e.printStackTrace();
}
}
/* This Runnable creates a Dialog and asks the user to download the update */
private Runnable showError = new Runnable(){
public void run(){
alertError = new AlertDialog.Builder(activity)
.setIcon(alertIcon)
.setTitle(alertTitleError)
.setMessage(alertMessageError)
.setCancelable(true)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
})
.show();
}
};
/* This Runnable creates an Error message*/
private Runnable showUpdate = new Runnable(){
public void run(){
alertUpdate = new AlertDialog.Builder(activity)
.setIcon(alertIcon)
.setTitle(alertTitle)
.setMessage(alertMessage)
.setCancelable(true)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Log.d(TAG, "TAG:Starting to download");
DownloadFilesTask downloadFile = new DownloadFilesTask();
downloadFile.execute(remoteApkUrl, localApkName);
}
})
.show();
}
};
private void checkupdate() {
if( alertUpdate!=null && alertUpdate.isShowing() ) { //(alertError!=null && alertError.isShowing()) ||
//There is already an download message
return;
}
Log.v(TAG, "Checking updates...");
try {
URL updateURL = new URL(versionUrl);
URLConnection conn = updateURL.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
/* Convert the Bytes read to a String. */
final String s = new String(baf.toByteArray());
/* Get current Version Number */
String curVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
String newVersion = s;
Log.d(TAG, "Current version is: " + curVersion + " and new one is: " + newVersion);
/* Is a higher version than the current already out? */
if (!curVersion.equals(newVersion)) {
/* Post a Handler for the UI to pick up and open the Dialog */
if(alertUpdate==null || !alertUpdate.isShowing()) {
if(alertError!=null && alertError.isShowing())
alertError.dismiss();
mHandler.post(showUpdate);
}
} else
Log.v(TAG, "The software is updated to the latest version: " + newVersion);
} catch (Exception e) {
e.printStackTrace();
// if(alertError==null || !alertError.isShowing())
// mHandler.post(showError);
}
}
private class DownloadFilesTask extends AsyncTask<String, Integer, Integer> {
private ProgressDialog mProgressDialog;
private String outFileName;
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(activity);
mProgressDialog.setMessage(progressMessage);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setCancelable(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.show();
}
@Override
protected Integer doInBackground(String... urls) {
String inFileName = urls[0];
outFileName = urls[1];
try {
//connecting to url
URL u = new URL(inFileName);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
//lenghtOfFile is used for calculating download progress
int lenghtOfFile = c.getContentLength();
//this is where the file will be seen after the download
OutputStream out = context.openFileOutput(outFileName, Context.MODE_WORLD_READABLE); //
//file input is from the url
InputStream in = c.getInputStream();
//here's the download code
byte[] buffer = new byte[1024];
int readLenght = 0;
long total = 0;
int lastProgress = 0;
while ((readLenght = in.read(buffer)) > 0) {
total += readLenght;
int cProgress = (int)((total*100)/lenghtOfFile);
if(cProgress != lastProgress) {
publishProgress((int)((total*100)/lenghtOfFile));
lastProgress = cProgress;
}
out.write(buffer, 0, readLenght);
}
out.flush();
out.close();
in.close();
Log.d(TAG, "Saved file with name: " + outFileName + " | Size: " + total);
} catch (Exception e) {
e.printStackTrace();
return 1;
}
return 0;
}
@Override
public void onProgressUpdate(Integer... args){
mProgressDialog.setProgress(args[0]);
}
@Override
protected void onPostExecute(Integer result) {
mProgressDialog.dismiss();
if(result == 0)
InstallFile(outFileName);
else
mHandler.post(showError);
}
}
private void InstallFile(String fileName) {
Log.d(TAG, "Installing file " + fileName);
File file = new File(context.getFilesDir(), fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
activity.startActivity(intent);
}
public boolean isEnabled() {
return enabled;
}
public void disable() {
enabled = false;
}
public void enable() {
enabled = true;
}
public void setTagPrefix(String tagPrefix) {
TAG = tagPrefix + " " + TAG_SUFFIX;
}
}
|
|
1 Comment
For screenshots: http://blog.fdev.eu/updatechecker/