Ответ 1
Как я и обещал здесь, это решение этой проблемы, без какого-либо принуждения к системе, кроме необходимости устанавливать все приложение в каталог /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;
}
}
}
- создайте в /src пакет com.example.instuninsthelper. Я добавил туда файлы ApplicationManager.java и OnInstalledPackage.java.
- вставил следующий код внутри класса ApplicationManager:
private OnDeletedPackage onDeletedPackage;
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(boolean succeeded) throws RemoteException {
if (onDeletedPackage != null) {
onDeletedPackage.packageDeleted(succeeded);
}
}
}
- создается под тем же пакетом com.example.instuninsthelper файл OnDeletedPackage.java со следующим кодом:
package com.example.instuninsthelper;
public interface OnDeletedPackage {
public void packageDeleted(boolean succeeded);
}
- в пакете 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;
}
- создать приложение в Eclipse и развернуть его в эмуляторе
- в эмуляторе: главная кнопкa > Настройки > приложения > ... удалить приложение (потому что оно не установлено в /system/app, и нам просто нужно генерировать файл apk)
- выполните следующие действия, чтобы запустить эмулятор (чтобы мы могли писать в /system/app; другое решение, которое я использовал, - это создание пользовательского ПЗУ с этим приложением, включенным в /system/app ):
- загрузите файл su здесь http://forum.xda-developers.com/showthread.php?t=682828http://forum.xda-developers.com/showthread.php?t=682828. Переименуйте его в su.zip
- затем с консоли: * adb shell mount -o rw, remount -t yaffs2/dev/block/mtdblock03/system * adb push su.zip/system/xbin/su * adb shell chmod 06755/system * adb shell chmod 06755/system/xbin/su
- с консоли, перейдите в каталог /bin проекта, затем введите: * adb push.apk/system/app
- наконец, всегда с консоли, введите: * adb shell am start -n com.example.silentinstuninst/com.example.silentinstuninst.MainActivity
- наслаждайтесь!