Androidにサイレントinstaller-from-apk-fileとunistaller-packageを実装したいと思います。このトピックは主にSOなどで議論されていますが、私が欠けている何らかの理由で適用できません。成功した場合は、スコープを達成するのは明らかに困難です。 Androidの重大なセキュリティ違反ですが、消費者市場ではなく、特別なプロジェクトに実装する必要があります。2つのアプローチがあります。
最初のケースでは、Froyoのソースコードを掘り下げましたが、@ hideマークの付いたメソッドで行き止まりになりました。 2回目は、最初にターミナルからのコマンドを試しました
adb Shell pm install /mnt/sdcard/HelloAndroid.apk
そして
adb Shell pm uninstall com.example.helloandroid
どちらも問題なく動作します。次に、次のコードを使用しました。開発は、ルート化されたエミュレーター(2.2-Froyo)でテストされています。
@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
try {
install = Runtime.getRuntime().exec("su\n");
DataOutputStream os = new DataOutputStream(install.getOutputStream());
os.writeBytes("pm install /mnt/sdcard/HelloAndroid.apk\n");
os.writeBytes("exit\n");
os.flush();
install.waitFor();
if (install.exitValue() == 0) {
Toast.makeText(MainActivity.this, "Success!", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(MainActivity.this, "Failure. Exit code: "+String.valueOf(install.exitValue()), Toast.LENGTH_LONG).show();
}
}
catch (InterruptedException e) {
logError(e);
}
catch (IOException e) {
logError(e);
}
break;
case R.id.btnUninstall:
try {
install = Runtime.getRuntime().exec("su\n");
install=Runtime.getRuntime().exec("pm uninstall "+txtPackageName.getText().toString()+"\n");
} catch (Exception e) {
logError(e);
}
break;
}
}
タイプミスやその他のトリムを回避するために、インストール用のコマンドのapkファイルパラメーターをハードコーディングしました。 'case R.id.btnInstall'では、コマンドは実行されず、出口は「Failure」にあり、出口値は1で、「クラスが見つかりません」を意味します。それが何を意味するのか分かりません...私はあなたの助けに感謝します!
編集:私はきれいな解決策を持っています、私は時間と正しい形式のコードができたらすぐにA-Zからの答えを投稿します!!
ここで約束したように、アプリケーション全体を/ system/appディレクトリにインストールする以外に、システムに強制することなく、この問題の解決策があります。私はフォローし、ここで優れた記事にいくつかの修正を行いました: http://paulononaka.wordpress.com/2011/07/02/how-to-install-a-application-in-background-on- Android / 。そのとき、記事で参照されているZipファイルをダウンロードしました(可能な限り同じクラス名を維持しようとしました)。
package com.example.silentinstuninst;
import Java.io.File;
import Java.lang.reflect.InvocationTargetException;
import com.example.instuninsthelper.ApplicationManager;
import com.example.instuninsthelper.OnDeletedPackage;
import com.example.instuninsthelper.OnInstalledPackage;
import Android.os.Bundle;
import Android.os.Environment;
import Android.app.Activity;
import Android.util.Log;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.widget.Button;
import Android.widget.EditText;
import Android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
Process install;
Button btnInstall, btnUninstall;
EditText txtApkFileName, txtPackageName;
public static final String TAG = "SilentInstall/Uninstall";
private static ApplicationManager am;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeValues();
}
private void initializeValues() {
btnInstall = (Button) findViewById(R.id.btnInstall);
btnUninstall = (Button) findViewById(R.id.btnUninstall);
txtApkFileName = (EditText) findViewById(R.id.txtApkFilePath);
txtPackageName = (EditText) findViewById(R.id.txtPackageName);
btnInstall.setOnClickListener(this);
btnUninstall.setOnClickListener(this);
try {
am = new ApplicationManager(this);
am.setOnInstalledPackage(new OnInstalledPackage() {
public void packageInstalled(String packageName, int returnCode) {
if (returnCode == ApplicationManager.INSTALL_SUCCEEDED) {
Log.d(TAG, "Install succeeded");
} else {
Log.d(TAG, "Install failed: " + returnCode);
}
}
});
am.setOnDeletedPackage(new OnDeletedPackage() {
public void packageDeleted(boolean succeeded) {
Log.d(TAG, "Uninstall succeeded");
}
});
} catch (Exception e) {
logError(e);
}
}
private void logError(Exception e) {
e.printStackTrace();
Toast.makeText(this, R.string.error+e.getMessage(), Toast.LENGTH_LONG).show();
}
@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
// InstallUninstall.Install(txtApkFileName.getText().toString());
try {
am.installPackage(Environment.getExternalStorageDirectory() +
File.separator + txtApkFileName.getText().toString());
} catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InvocationTargetException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // install package
break;
case R.id.btnUninstall:
// InstallUninstall.Uninstall(txtPackageName.getText().toString());
try {
am.uninstallPackage(txtPackageName.getText().toString());
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
}
break;
}
}
}
private OnDeletedPackage onDeletedPackage;
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(boolean succeeded) throws RemoteException {
if (onDeletedPackage != null) {
onDeletedPackage.packageDeleted(succeeded);
}
}
}
package com.example.instuninsthelper;
public interface OnDeletedPackage {
public void packageDeleted(boolean succeeded);
}
package Android.content.pm;
public interface IPackageDeleteObserver extends Android.os.IInterface {
public abstract static class Stub extends Android.os.Binder implements Android.content.pm.IPackageDeleteObserver {
public Stub() {
throw new RuntimeException("Stub!");
}
public static Android.content.pm.IPackageDeleteObserver asInterface(Android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}
public Android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}
public boolean onTransact(int code, Android.os.Parcel data, Android.os.Parcel reply, int flags)
throws Android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}
public abstract void packageDeleted(boolean succeeded)
throws Android.os.RemoteException;
}
わからないが、ただのアイデア:
コマンドを実行したり、入力を介してプロセスに追加のデータを提供したりするのではなく、傑出したものを書き込んでいると思います。私はそれがすべきだと思います:
Runtime.getRuntime().exec("pm install /mnt/sdcard/HelloAndroid.apk\n");
お役に立てれば。
_/system/app
_ディレクトリへのインストールは、基本的にrootを必要とすることと同じです。
あなたがルートを持っていると仮定して、チェックアウト RootTools 。次に、次のことができます。
_if (RootTools.isAccessGiven()) {
CommandCapture command = new CommandCapture(0, "pm install " + PATH_TO_APK);
RootTools.getShell(true).add(command).waitForFinish();
}
_
waitForFinish()
はブロッキング呼び出しであることに注意してください。
これは、PackageManagerを使用して直接行うこともできます(ルートアクセスが必要です)。
これを参照してください: http://forum.xda-developers.com/showthread.php?t=171165
Runtime.getRuntime()。exec( "pm install /mnt/sdcard/HelloAndroid.apk\n");
これは私にとってはうまくいきますが、さらに2つの詳細を行う必要があります。
AndroidManifest.xmlにAndroid:sharedUserId = "Android.uid.system"を追加します。
システムキーでapkに署名しました。
しかし、このようにインストールが成功したかどうかを判断する方法がないように思われるので、後で@Gingerの方法を試してみます。
まだ問題を抱えているすべての人のために:あなたは根ざしたデバイスを必要とし、使用します
Process result = Runtime.getRuntime().exec("pm install -r -d MyApp.apk /system/app")
結果コード9(エラーコード9)を取得している場合は、apkをデバイスから削除し、プッシュバックする必要があります(プッシュではなくINSTAL!)。
デバイスシェルに移動し、apkをプッシュします
launcher=MyApp.apk
$adb Shell su -c "mount -o remount,rw -t rfs /dev/stl5 /system"
$adb Push $launcher /sdcard/$launcher
$adb Shell su -c "chmod 644 /system/app/$launcher"
これで、エラーが発生することなくpminstallを使用できるようになりました。それが誰かを助けることを願っています。