原方案在這裏https://zhuanlan.zhihu.com/p/21585970,下面寫具體實現
核心代碼及原理通過adb shell 中的pm指令來操作,主要是通過process去實現命令
String cmd = "pm install /sdcard/xxx.apk"//寫要執行的命令,卸載爲pm uninstall com.xxx.xxx
try {
if("".equals(cmd)) {
throw new NullPointerException();
}
String consoleReply = Runtime.getRuntime().exec(cmd).toString();
return consoleReply;
} catch (IOException e) {
e.printStackTrace();
return MyService.this.ERROR;
}
運行這段代碼需要system uid標識及系統簽名
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.xxx"
android:sharedUserId="android.uid.system">
生成apk後需要系統簽名
java -jar signapk.jar platform.x509.pem platform.pk8 app-release.apk signapp.apk
現在遇到的項目是給系統做的,所以打算使用aidl方式去調用該接口,當然用廣播做也可以
下面是定義aidl的內容,定義了一個接口,和一個運行的方法需要實現
interface AidlShellCmd {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);
String runCmd(String cmd);
}
Server端,
MyService.java
public class MyService extends Service {
public static String ERROR = "ERROR";
private AidlShellCmd aidlShellCmd = new AidlShellCmd.Stub() {
@Override
public String runCmd(String cmd) throws RemoteException {
try {
if("".equals(cmd)) {
throw new NullPointerException();
}
String consoleReply = Runtime.getRuntime().exec(cmd).toString();
return consoleReply;
} catch (IOException e) {
e.printStackTrace();
return MyService.this.ERROR;
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return aidlShellCmd.asBinder();
}
}
Client端,
Mainactivity.java
public class MainActivity extends AppCompatActivity implements ServiceConnection, View.OnClickListener {
private AidlShellCmd aidlShellCmd;
private Button bt_uninstall, bt_install;
private String cmd = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_uninstall = (Button) findViewById(R.id.bt_uninstall);
bt_install = (Button) findViewById(R.id.bt_install);
Intent intent = new Intent("com.xxx.xxx");//action
ComponentName componentName = new ComponentName("com.xxx.xxx", "com.xxx.xxx.MyService");//Server端的Service設置的包名
intent.setComponent(componentName);
bindService(intent, this, Context.BIND_AUTO_CREATE);
bt_uninstall.setOnClickListener(this);
bt_install.setOnClickListener(this);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlShellCmd = AidlShellCmd.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_uninstall:
try {
cmd = "pm uninstall cc.xxx.xxx";
Toast.makeText(this, "1" + aidlShellCmd.runCmd(cmd), Toast.LENGTH_LONG).show();
cmd = "";
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.bt_install:
cmd = "pm install /sdcard/xxx.apk";
try {
Toast.makeText(this, "1" + aidlShellCmd.runCmd(cmd), Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
@Override
protected void onDestroy() {
unbindService(this);
super.onDestroy();
}
}
以上,就能實現靜默安裝和卸載,其實這邊使用的cmd是還可以實現更多的功能比如,adb shell中的am、wm指令