野良アプリに自動更新のような機能を実装する

アプリ起動中に更新チェックとapkファイルのダウンロードを行い、インストール画面を表示する方法。
公式マーケットのようにユーザーの操作を一切必要とせずアプリを更新するものではありません。
動作としてはAdobe AIRの自動更新に近いものです。

 

まずはバージョンチェック用のxml
バージョン情報と最新版apkファイルのurlを記載します 。

<?xml version="1.0" encoding="utf-8"?>
<update>
  <versionCode>4</versionCode>
  <versionName>1.2</versionName>
  <url>http://myserver.net/update.apk</url>
  <description><![CDATA[
    test
  ]]></description>
</update>

 

自動更新したいアプリ本体のソースはだいたい以下のようになります。最新版apkと上記xmlをサーバにアップロードしてupdateXmlUrlに指定。

public class AutoUpdateTestActivity extends Activity implements AutoUpdateEventListener {

	private final String updateXmlUrl = "http://myserver.net/update.xml";

	private Handler handler;
	private Updater updater;

	public void onCreate(Bundle savedInstanceState) {

		handler = new Handler();
//1.更新チェック
		updater = new Updater(this, updateXmlUrl);
		updater.updateCheck();
	}

	@Override
	public void onUpdateAvailable() {
//2.アップデートダイアログの表示
		handler.post(new Runnable() {
			@Override
			public void run() {
				showUpdateDialog();
			}
		});
	}

	private void showUpdateDialog(){
		new AlertDialog.Builder(this)
			.setTitle("Update")
			.setIcon(R.drawable.ic_launcher)
			.setMessage("Update available")
			.setPositiveButton("Update",
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
//3.ダウンロード開始
						updater.downloadApk();
					}
				})
			.setNegativeButton("Cancel", null)
			.show();
	}

	@Override
	public void onUpdateApkDownloadComplete() {
//4.インストール
		handler.post(new Runnable() {
			@Override
			public void run() {
				updater.installApk();
			}
		});
	}

	public void onDestroy() {
//5.テンポラリファイルの削除
		updater.deleteTempApkFile();
	}
}

 

Updaterは長いので一部抜粋。
アプリのversionCodeとversionNameを取得

PackageManager pm = activity.getPackageManager();
String packageName = activity.getPackageName();
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_META_DATA);

int versionCode = packageInfo.versionCode;
String versionName = packageInfo.versionName;

 

更新用xmlからversionCodeとversionName、apkファイルのurlを取得

HashMap<String, String> map = new HashMap<String, String>();

InputStream is = new URL(updateXmlUrl).openConnection().getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);

DocumentBuilderFactory document_builder_factory = DocumentBuilderFactory.newInstance();
DocumentBuilder document_builder = document_builder_factory.newDocumentBuilder();
Document document = document_builder.parse(bis);
Element root = document.getDocumentElement();

if(root.getTagName().equals("update")){
  NodeList nodelist = root.getChildNodes();
  for (int j=0;j<nodelist.getLength();j++){
    Node node = nodelist.item(j);
    if(node.getNodeType()==Node.ELEMENT_NODE){
      Element element = (Element) node;
      String name = element.getTagName();
      String value = element.getTextContent().trim();
      map.put(name, value);
    }
  }

  int versionCode = Integer.parseInt(map.get("versionCode"));
  String versionName = map.get("versionName");
  String updateApkUrl = map.get("url");
}

 

apkファイルのダウンロード

URL url = new URL(updateApkUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
InputStream is = urlConnection.getInputStream();

File cacheDir = getExternalCacheDir();
File tempApkFile = File.createTempFile("apk", ".apk", cacheDir);
FileOutputStream os = new FileOutputStream(tempApkFile);

byte[] buffer = new byte[1024];
int bufferLength = 0;

while ( (bufferLength = is.read(buffer)) > 0 ) {
	os.write(buffer, 0, bufferLength);
}
os.close();
is.close();

 

インストール画面の表示

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri dataUri = Uri.fromFile(tempApkFile);
intent.setDataAndType(dataUri, "application/vnd.android.package-archive");
startActivity(intent);

 

AutoUpdateEventListenerやその他細かい部分はソースをダウンロードしてください。エラー処理などはかなり適当です。それとインストール用のapkファイルを本体側に保存するとなぜかインストールできませんでした。AndroidManifest.xmlが読み込めないとか何とか・・・。

ソースダウンロード: AutoUpdateTest_src.zip

おすすめ

2件のフィードバック

  1. anciel より:

    参考にさせていただきました。
    UtilのurlToOutputStream関数の、
    urlConnection.setDoOutput(true); を削除したらうまくいきました。
    SDカードがないNexus7でテストしましたが、インストーラーも起動しました。

    • petit より:

      コメントありがとうございます。setDoOutputはPOSTのときだけ必要でしたか。
      インストーラが起動しないのは何かの設定ミスか、あるいはAndroid2.3の頃のSDKが原因かもしれませんね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です