web-dev-qa-db-ja.com

Android)のシェルコマンドからインストール/アンインストール

Androidにサイレントinstaller-from-apk-fileとunistaller-packageを実装したいと思います。このトピックは主にSOなどで議論されていますが、私が欠けている何らかの理由で適用できません。成功した場合は、スコープを達成するのは明らかに困難です。 Androidの重大なセキュリティ違反ですが、消費者市場ではなく、特別なプロジェクトに実装する必要があります。2つのアプローチがあります。

  1. packageManagerインストーラーを微調整することにより(実際には、ユーザー受け入れダイアログボックスを削除するためだけに)、ソースコード(AOSPまたはCyanogen modなど)からカスタムROMを生成します)。
  2. スーパーユーザーとしてプロセスを作成し、「adb Shellpminstall」を実行してプログラムで実行します。以前に/ system/xbinに「su」をインストールし、実行時にRootTools.rootIsAvailable()をテストしました。

最初のケースでは、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からの答えを投稿します!!

10
Ginger Opariti

ここで約束したように、アプリケーション全体を/ system/appディレクトリにインストールする以外に、システムに強制することなく、この問題の解決策があります。私はフォローし、ここで優れた記事にいくつかの修正を行いました: http://paulononaka.wordpress.com/2011/07/02/how-to-install-a-application-in-background-on- Android / 。そのとき、記事で参照されているZipファイルをダウンロードしました(可能な限り同じクラス名を維持しようとしました)。

  1. 新しいプロジェクトとメインアクティビティをエントリポイントとして作成しました

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;
           }    
    }
}
  1. / srcにパッケージcom.example.instuninsthelperを作成します。そこにApplicationManager.JavaファイルとOnInstalledPackage.Javaファイルを追加しました
  2. applicationManagerクラス内に次のコードを挿入しました。

private OnDeletedPackage onDeletedPackage;
class PackageDeleteObserver extends IPackageDeleteObserver.Stub { 

        public void packageDeleted(boolean succeeded) throws RemoteException {
            if (onDeletedPackage != null) {
                onDeletedPackage.packageDeleted(succeeded);
            }
        }

    }
  1. 同じcom.example.instuninsthelperパッケージの下に、次のコードでファイルOnDeletedPackage.Javaを作成しました。

package com.example.instuninsthelper;
public interface OnDeletedPackage {
    public void packageDeleted(boolean succeeded);
}
  1. android.content.pmパッケージ(名前空間は変更しないでください)で、IPackageDeleteObserver.Javaを変更した結果、次のようになりました。

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;
}
  1. eclipseでアプリケーションをビルドし、エミュレーターにデプロイします
  2. エミュレーター内:ホームボタン>設定>アプリケーション> ...アプリケーションをアンインストールします(/ system/appにインストールされておらず、apkファイルの生成が必要なため)
  3. エミュレーターをルート化するには、次の手順を実行します(/ system/appに書き込むことができるようにします。私が使用した他のソリューションは、このアプリを/ systemに含めてカスタムROMを生成することです。/app):
  4. コンソールから、プロジェクトの/ binディレクトリに移動し、次のように入力します。* adb Push .apk/system/app
  5. 最後に、常にコンソールから次のように入力します。* adb Shell am start -n com.example.silentinstuninst/com.example.silentinstuninst.MainActivity
  6. 楽しい!
6
Ginger Opariti

わからないが、ただのアイデア:

コマンドを実行したり、入力を介してプロセスに追加のデータを提供したりするのではなく、傑出したものを書き込んでいると思います。私はそれがすべきだと思います:

Runtime.getRuntime().exec("pm install /mnt/sdcard/HelloAndroid.apk\n"); 

お役に立てれば。

1
inigoD

_/system/app_ディレクトリへのインストールは、基本的にrootを必要とすることと同じです。

あなたがルートを持っていると仮定して、チェックアウト RootTools 。次に、次のことができます。

_if (RootTools.isAccessGiven()) {
    CommandCapture command = new CommandCapture(0, "pm install " + PATH_TO_APK);
    RootTools.getShell(true).add(command).waitForFinish();
}
_

waitForFinish()はブロッキング呼び出しであることに注意してください。

1
nickaknudson

これは、PackageManagerを使用して直接行うこともできます(ルートアクセスが必要です)。

  • パブリックにインターフェイスを持つplatform-sdkを使用してアプリを作成します(アプリを作成またはダウンロードし、Eclipseを構成します)
  • アプリで、サイレントインストール/削除を可能にする非表示のAPI関数を直接呼び出します。
  • APKを/ system/appにコピーしてシステムアプリとしてデバイスにインストールします(ルートが必要です)

これを参照してください: http://forum.xda-developers.com/showthread.php?t=171165

0
RvdK

Runtime.getRuntime()。exec( "pm install /mnt/sdcard/HelloAndroid.apk\n");

これは私にとってはうまくいきますが、さらに2つの詳細を行う必要があります。

  1. AndroidManifest.xmlにAndroid:sharedUserId = "Android.uid.system"を追加します。

  2. システムキーでapkに署名しました。

    しかし、このようにインストールが成功したかどうかを判断する方法がないように思われるので、後で@Gingerの方法を試してみます。

0
yiyang

まだ問題を抱えているすべての人のために:あなたは根ざしたデバイスを必要とし、使用します

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を使用できるようになりました。それが誰かを助けることを願っています。

0
jirkarrrr