Lollipopで実装された新しいapkのインストール形式
5.0からinstall sessionという新しいインストール方法が実装されている。
どういうものかというと、
- apkインストール時に一時コピーはつくらずに、フラッシュでバイスに直接書き込む
- その結果、いろいろ効率的になって良い
InstallSessionとかいうらしい。
詳細は別ポストで書く予定。とりあえず試し方。
簡単な試し方
pmコマンド
pmコマンドもすでに対応していて、pm install hogehoge.apk
ではなくて以下のようにする。
やってることは、
- セッションをつくって、
- インスコしたいapk登録して、
- セッションコミット!
の3段階。簡単。
コマンドの例は以下。
$ pm install-create -i ringo
Success: created install session [1914420212]
$ pm install-write 1914420212 gorira <インスコしたいapkのパス>
Success: streamed 279430 bytes
$ pm install-commit 1914420212
Success
Successと出たらインスコ成功。
あと、$ pm install-abandon セッションID
でセッションの破棄。
詳細はpmコマンドのソース見ればわかると思います。
API
ちなみにinstallsessionは公開APIです。
https://developer.android.com/reference/android/content/pm/PackageInstaller.html
ただしandroid.permission.INSTALL_PACKAGES(signature|system)が必要っぽいので、以下試される方は、priv-appにつっこんでくらはい。
以下スニペットです。
private int createSession() {
final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallLocation(PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
int sessionId = -1;
try {
sessionId = packageInstaller.createSession(params);
} catch (IOException e) {}
PackageInstaller.SessionCallback sessionCallback = new
PackageInstaller.SessionCallback() {
@Override
public void onCreated(int i) {
Log.v("hoge", "SessionCallback#onCreate : " + i);
}
@Override
public void onBadgingChanged(int i) {
Log.v("hoge", "SessionCallback#onBadgingChanged : " + i);
}
@Override
public void onActiveChanged(int i, boolean b) {
Log.v("hoge", "SessionCallback#onActiveChanged : "
+ i + ", boolean :" + b);
}
@Override
public void onProgressChanged(int i, float v) {
Log.v("hoge", "SessionCallback#onProgressChanged :" + i + ", " + v);
}
@Override
public void onFinished(int i, boolean b) {
Log.v("hoge", "SessionCallback#onFinished : " + i + ", boolean :" + b);
}
};
packageInstaller.registerSessionCallback(sessionCallback);
return sessionId;
}
private int writeSession(final int sessionId) {
long sizeBytes = -1;
final String splitName = 適当な文字列;
final String apkPath = インスコしたいapkのパス;
final File file = new File(apkPath);
if (file.isFile()) {
sizeBytes = file.length();
}
Log.v("hoge", "apk size :" + sizeBytes);
PackageInstaller.Session session = null;
InputStream in = null;
OutputStream out = null;
try {
try {
session = packageInstaller.openSession(sessionId);
in = new FileInputStream(apkPath);
out = session.openWrite(splitName, 0, sizeBytes);
int total = 0;
byte[] buffer = new byte[65536];
int c;
while ((c = in.read(buffer)) != -1) {
total += c;
out.write(buffer, 0, c);
}
session.fsync(out);
} catch (IOException e) {
}
return 0;
} finally {
try {
out.close();
in.close();
session.close();
} catch (IOException e) {}
}
}
private void commitSession(final int sessionId) {
PackageInstaller.Session session = null;
try {
try {
session = packageInstaller.openSession(sessionId);
} catch (IOException e) {
}
Intent intent = new Intent(this, MainActivity.class);
PendingIntent sender = PendingIntent.getActivity(this, 0, intent, 0);
session.commit(sender.getIntentSender());
} finally {
session.close();
}
}