Estou tentando instalar o apk no sistema silenciosamente. Meu aplicativo está localizado em / system / app e recebeu a permissão "android.permission.INSTALL_PACKAGES"
No entanto, não consigo encontrar em nenhum lugar como usar essa permissão. Tentei copiar arquivos para / data / app e não tive sucesso. Também tentei usar este código
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///sdcard/app.apk"),
"application/vnd.android.package-archive");
startActivity(intent);
Mas este código abre a caixa de diálogo de instalação padrão. Como posso instalar o aplicativo silenciosamente sem root com concedido android.permission.INSTALL_PACKAGES
?
PS Estou escrevendo um aplicativo que irá instalar muitos apks da pasta no sistema na primeira inicialização (substitua o assistente de configuração). Preciso tornar o firmware mais leve.
Se você acha que estou escrevendo um vírus: Todos os programas são instalados em / data / app. A permissão Install_packages só pode ser concedida a programas de nível de sistema localizados em / system / app ou assinados com a chave do sistema. Portanto, o vírus não pode chegar lá.
Como disse http://www.mail-archive.com/[email protected]/msg06281.html, os aplicativos PODEM ser instalados silenciosamente se tiverem permissão install_packages. Além disso, você não precisa da permissão Install_packages para instalar pacotes não silenciosamente. Além disso, http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
fonte
Respostas:
Sua primeira aposta é dar uma olhada no PackageInstaller nativo do Android . Eu recomendaria modificar esse aplicativo da maneira que você quiser ou apenas extrair a funcionalidade necessária.
Especificamente, se você olhar para PackageInstallerActivity e seu método
onClickListener
:public void onClick(View v) { if(v == mOk) { // Start subactivity to actually install the application Intent newIntent = new Intent(); ... newIntent.setClass(this, InstallAppProgress.class); ... startActivity(newIntent); finish(); } else if(v == mCancel) { // Cancel and finish finish(); } }
Em seguida, você notará que o instalador real está localizado na classe InstallAppProgress . Inspecionando essa classe você verá que
initView
é a função de instalação do núcleo, ea última coisa que ele faz é chamada paraPackageManager
'sinstallPackage
função:public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); }
A próxima etapa é inspecionar PackageManager , que é uma classe abstrata. Você encontrará
installPackage(...)
função lá. A má notícia é que está marcado com @hide. Isso significa que não está disponível diretamente (você não conseguirá compilar com a chamada a este método)./** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName);
Mas você poderá acessar esses métodos por meio de reflexão.
Se você estiver interessado em como
PackageManager
ainstallPackage
função de é implementada, dê uma olhada em PackageManagerService .Resumo
Você precisará obter o objeto gerenciador de pacotes por meio
Context
degetPackageManager()
. Em seguida, você chamará ainstallPackage
função por meio de reflexão.fonte
LogCat
para logs de permissão relacionados.Eu verifiquei como o ADB instala aplicativos.
- Ele copia o APK para / data / local / tmp
- ele executa 'shell: pm install /data/local/tmp/app.apk'
Tentei replicar esse comportamento fazendo: (no pc, usando um cabo USB)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Isso funciona. O aplicativo está instalado.
Eu fiz um aplicativo (chamado AppInstall) que deve instalar o outro aplicativo.
(instalado normalmente, dispositivo sem acesso root)
Sim:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Mas isso dá o erro:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
Parece que o erro é lançado por pm, não por AppInstall.
Porque a SecurityException não é capturada pelo AppInstall e o aplicativo não falha.
Eu tentei a mesma coisa em um dispositivo com acesso root (mesmo aplicativo e AppInstall) e funcionou perfeitamente.
(Também normalmente instalado, não em / system ou qualquer coisa)
AppInstall nem mesmo pediu permissão de root.
Mas isso é porque o shell está sempre em
#
vez de$
naquele dispositivo.A propósito, você precisa de root para instalar um aplicativo em / system, correto?
Eu tentei remount adb no dispositivo sem root e obteve:
remount failed: Operation not permitted.
É por isso que eu não pude tentar o / system no dispositivo sem root.
Conclusão: você deve usar um dispositivo com root
Espero que isso ajude :)
fonte
su
)Eu tenho implementado a instalação sem o consentimento do usuário recentemente - era um aplicativo de quiosque para API nível 21+ onde eu tinha controle total sobre o ambiente.
Os requisitos básicos são
O método a seguir lê e instala o APK do InputStream:
public static boolean installPackage(Context context, InputStream in, String packageName) throws IOException { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.setAppPackageName(packageName); // set params int sessionId = packageInstaller.createSession(params); PackageInstaller.Session session = packageInstaller.openSession(sessionId); OutputStream out = session.openWrite("COSU", 0, -1); byte[] buffer = new byte[65536]; int c; while ((c = in.read(buffer)) != -1) { out.write(buffer, 0, c); } session.fsync(out); in.close(); out.close(); Intent intent = new Intent(context, MainActivity.class); intent.putExtra("info", "somedata"); // for extra data if needed.. Random generator = new Random(); PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT); session.commit(i.getIntentSender()); return true; }
O código a seguir chama a instalação
try { InputStream is = getResources().openRawResource(R.raw.someapk_source); installPackage(MainActivity.this, is, "com.example.apk"); } catch (IOException e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); }
para que tudo funcione, você precisa desesperadamente de
INSTALL_PACKAGES
permissão, ou o código acima falhará silenciosamente<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
para obter essa permissão, você deve instalar seu APK como um aplicativo de sistema que REQUER root (no entanto, APÓS instalar seu aplicativo de atualização, ele parece funcionar SEM root)
Para instalar como aplicativo do sistema, criei um APK assinado e empurrei-o com
adb push updater.apk /sdcard/updater.apk
e, em seguida, movido para
system/priv-app
- o que requer remontar FS (é por isso que a raiz é necessária)adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
por algum motivo ele não funcionou com a versão de depuração simples, mas o logcat mostra informações úteis se seu aplicativo
priv-app
não for selecionado por algum motivo.fonte
Você deve definir
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
em seu manifesto, se você estiver na partição do sistema (/ system / app) ou se tiver seu aplicativo assinado pelo fabricante, você terá permissão INSTALL_PACKAGES.
Minha sugestão é criar um pequeno projeto android com nível de compatibilidade 1.5 usado para chamar installPackages via reflexão e exportar um jar com métodos para instalar pacotes e chamar os métodos reais. Então, importando o jar em seu projeto, você estará pronto para instalar os pacotes.
fonte
Tentei no Android 4.2.2 com root e este método funciona para mim:
private void installApk(String filename) { File file = new File(filename); if(file.exists()){ try { final String command = "pm install -r " + file.getAbsolutePath(); Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
fonte
Não tinha ideia de como fazer isso, pois ninguém respondeu naquela vez, e não encontrei documentação sobre essa permissão. Então, encontrei minha própria solução. É pior que o seu, mas é uma solução de qualquer maneira.
Eu instalei o busybox, que definiu 777 permissões para / data / app (não me importo com segurança). Em seguida, basta executar "busybox install" do aplicativo. Isso funciona, mas tem um grande vazamento de segurança. Se você definir as permissões 777, nenhuma raiz será necessária.
fonte
Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
Você pode usar a API oculta
android.content.pm.IPackageInstallObserver
por reflexão:public class PackageManagement { public static final int INSTALL_REPLACE_EXISTING = 0x00000002; public static final int INSTALL_SUCCEEDED = 1; private static Method installPackageMethod; private static Method deletePackageMethod; static { try { installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) { try { installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName); } catch (Exception e) { e.printStackTrace(); } } }
Importe
android.content.pm.IPackageInstallObserver
para o seu projeto. Seu aplicativo deve ser do sistema. Você deve ativar a permissãoandroid.permission.INSTALL_PACKAGES
em seu arquivo de manifesto.fonte
Você pode simplesmente usar o comando adb install para instalar / atualizar o APK silenciosamente. O código de amostra está abaixo
public static void InstallAPK(String filename){ File file = new File(filename); if(file.exists()){ try { String command; filename = StringUtil.insertEscape(filename); command = "adb install -r " + filename; Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
fonte
Pré-requisito:
Seu APK precisa ser assinado pelo sistema, conforme apontado corretamente anteriormente. Uma maneira de conseguir isso é construir você mesmo a imagem AOSP e adicionar o código-fonte à construção.
Código:
Depois de instalado como um aplicativo do sistema, você pode usar os métodos do gerenciador de pacotes para instalar e desinstalar um APK da seguinte forma:
Instalar:
public boolean install(final String apkPath, final Context context) { Log.d(TAG, "Installing apk at " + apkPath); try { final Uri apkUri = Uri.fromFile(new File(apkPath)); final String installerPackageName = "MyInstaller"; context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
Desinstalar:
public boolean uninstall(final String packageName, final Context context) { Log.d(TAG, "Uninstalling package " + packageName); try { context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
Para ter um retorno de chamada depois que seu APK for instalado / desinstalado, você pode usar isto:
/** * Callback after a package was installed be it success or failure. */ private class InstallObserver implements IPackageInstallObserver { @Override public void packageInstalled(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully installed package " + packageName); callback.onAppInstalled(true, packageName); } else { Log.e(TAG, "Failed to install package."); callback.onAppInstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback after a package was deleted be it success or failure. */ private class DeleteObserver implements IPackageDeleteObserver { @Override public void packageDeleted(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully uninstalled package " + packageName); callback.onAppUninstalled(true, packageName); } else { Log.e(TAG, "Failed to uninstall package."); callback.onAppUninstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback to give the flow back to the calling class. */ public interface InstallerCallback { void onAppInstalled(final boolean success, final String packageName); void onAppUninstalled(final boolean success, final String packageName); }
===> Testado em Android 8.1 e funcionou bem.
fonte
Fiz um aplicativo de teste para instalações silenciosas, usando o método PackageManager.installPackage.
Obtive o método installPackage por meio de reflexão e fiz a interface android.content.pm.IPackageInstallObserver na minha pasta src (porque está oculto no pacote android.content.pm).
Quando executo installPackage, recebo SecurityException com indicação de string, que meu aplicativo não tem android.permission.INSTALL_PACKAGES, mas é definido em AndroidManifest.xml.
Então, eu acho que não é possível usar esse método.
PS. Eu testei no Android SDK 2.3 e 4.0. Talvez funcione com versões anteriores.
fonte
Experimente
LD_LIBRARY_PATH=/vendor/lib:/system/lib
antes de instalar. Isso funciona bem.fonte
Um aplicativo de terceiros não pode instalar um aplicativo Android suavemente. No entanto, um aplicativo de terceiros pode solicitar que o sistema operacional Android instale um aplicativo.
Portanto, você deve definir isso:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive"); startActivity(intent);
Você também pode tentar instalá-lo como um aplicativo do sistema para conceder a permissão e ignorar esta definição. (Root Obrigatório)
Você pode executar o seguinte comando em seu aplicativo de terceiros para instalar um aplicativo no dispositivo com acesso root.
O código é:
private void installApk(String filename) { File file = new File(filename); if(file.exists()){ try { final String command = "pm install -r " + file.getAbsolutePath(); Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command }); proc.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }
Espero que esta resposta seja útil para você.
fonte
É possível fazer uma instalação silenciosa no Android 6 e superior. Usando a função fornecida na resposta por Boris Treukhov, ignore todo o resto do post, o root também não é necessário.
Instale seu aplicativo como administrador do dispositivo, você pode ter o modo quiosque completo com instalação silenciosa de atualizações em segundo plano.
fonte
Eu verifiquei todas as respostas, a conclusão parece ser que você deve ter acesso root ao dispositivo primeiro para fazê-lo funcionar.
Mas então eu achei esses artigos muito úteis. Já que estou fazendo dispositivos "próprios".
Como atualizar o aplicativo Android silenciosamente, sem interação do usuário
Proprietário do dispositivo Android - aplicativo mínimo
Aqui está a documentação do Google sobre "dispositivo gerenciado"
Dispositivo totalmente gerenciado
fonte
você pode usar isso no terminal ou shell
adb shell install -g MyApp.apk
veja mais em Develope google
fonte
! / bin / bash
f=/home/cox/myapp.apk #or $1 if input from terminal. #backup env var backup=$LD_LIBRARY_PATH LD_LIBRARY_PATH=/vendor/lib:/system/lib myTemp=/sdcard/temp.apk adb push $f $myTemp adb shell pm install -r $myTemp #restore env var LD_LIBRARY_PATH=$backup
Isso funciona para mim. Eu executo isso no ubuntu 12.04, no terminal shell.
fonte