From 0d27afb88f77abae658b060d9c396816fd1e12e4 Mon Sep 17 00:00:00 2001 From: tiann <923551233@qq.com> Date: Sat, 9 Jun 2018 23:12:01 +0800 Subject: [PATCH] [VXP]: Feature, Google service support. --- .../main/java/io/virtualapp/gms/FakeGms.java | 412 ++++++++++++++++++ .../virtualapp/settings/SettingsActivity.java | 28 +- .../app/src/main/res/values-es/strings.xml | 13 +- .../app/src/main/res/values-fr/strings.xml | 13 +- .../app/src/main/res/values-ru/strings.xml | 12 + .../src/main/res/values-zh-rCN/strings.xml | 12 +- .../app/src/main/res/values/strings.xml | 13 +- .../src/main/res/xml/settings_preferences.xml | 10 +- 8 files changed, 484 insertions(+), 29 deletions(-) create mode 100644 VirtualApp/app/src/main/java/io/virtualapp/gms/FakeGms.java diff --git a/VirtualApp/app/src/main/java/io/virtualapp/gms/FakeGms.java b/VirtualApp/app/src/main/java/io/virtualapp/gms/FakeGms.java new file mode 100644 index 000000000..976db09b7 --- /dev/null +++ b/VirtualApp/app/src/main/java/io/virtualapp/gms/FakeGms.java @@ -0,0 +1,412 @@ +package io.virtualapp.gms; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.util.Log; + +import com.lody.virtual.client.core.InstallStrategy; +import com.lody.virtual.client.core.VirtualCore; +import com.lody.virtual.os.VEnvironment; +import com.lody.virtual.remote.InstallResult; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import io.virtualapp.R; +import io.virtualapp.abs.ui.VUiKit; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** + * @author weishu + * @date 2018/6/9. + */ +public class FakeGms { + + private static final String TAG = "FakeGms"; + + private static final String GMS_CONFIG_URL = "http://vaexposed.weishu.me/gms.json"; + + private static final String GMS_PKG = "com.google.android.gms"; + private static final String GSF_PKG = "com.google.android.gsf"; + private static final String STORE_PKG = "com.android.vending"; + private static final String FAKE_GAPPS_PKG = "com.thermatk.android.xf.fakegapps"; + + private static ExecutorService executorService = Executors.newSingleThreadExecutor(); + + public static void uninstallGms(Activity activity) { + if (activity == null) { + return; + } + + AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setTitle(R.string.uninstall_gms_title) + .setMessage(R.string.uninstall_gms_content) + .setPositiveButton(R.string.uninstall_gms_ok, ((dialog1, which1) -> { + ProgressDialog dialog = new ProgressDialog(activity); + dialog.show(); + VUiKit.defer().when(() -> { + VirtualCore.get().uninstallPackage(GMS_PKG); + VirtualCore.get().uninstallPackage(GSF_PKG); + VirtualCore.get().uninstallPackage(STORE_PKG); + VirtualCore.get().uninstallPackage(FAKE_GAPPS_PKG); + }).then((v) -> { + dialog.dismiss(); + AlertDialog hits = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setTitle(R.string.uninstall_gms_title) + .setMessage(R.string.uninstall_gms_success) + .setPositiveButton(android.R.string.ok, null) + .create(); + showDialog(hits); + + }).fail((v) -> { + dialog.dismiss(); + }); + + })) + .setNegativeButton(android.R.string.cancel, null) + .create(); + showDialog(failDialog); + } + + public static boolean isAlreadyInstalled(Context context) { + if (context == null) { + return false; + } + + boolean alreadyInstalled = true; + if (!VirtualCore.get().isAppInstalled(GMS_PKG)) { + alreadyInstalled = false; + } + if (!VirtualCore.get().isAppInstalled(GSF_PKG)) { + alreadyInstalled = false; + } + if (!VirtualCore.get().isAppInstalled(STORE_PKG)) { + alreadyInstalled = false; + } + if (!VirtualCore.get().isAppInstalled(FAKE_GAPPS_PKG)) { + alreadyInstalled = false; + } + return alreadyInstalled; + } + + public static void installGms(Activity activity) { + + if (activity == null) { + return; + } + + AlertDialog alertDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setTitle(R.string.install_gms_title) + .setMessage(R.string.install_gms_content) + .setPositiveButton(android.R.string.ok, ((dialog, which) -> { + // show a loading dialog and start install gms. + + ProgressDialog progressDialog = new ProgressDialog(activity); + progressDialog.setCancelable(false); + progressDialog.show(); + + executorService.submit(() -> { + String failMsg = installGmsInternal(activity, progressDialog); + Log.i(TAG, "install gms result: " + failMsg); + try { + progressDialog.dismiss(); + } catch (Throwable e) { + e.printStackTrace(); + } + + if (failMsg == null) { + activity.runOnUiThread(() -> { + AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setTitle(R.string.install_gms_title) + .setMessage(R.string.install_gms_success) + .setPositiveButton(android.R.string.ok, null) + .create(); + showDialog(failDialog); + }); + } else { + activity.runOnUiThread(() -> { + AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setTitle(R.string.install_gms_fail_title) + .setMessage(R.string.install_gms_fail_content) + .setPositiveButton(R.string.install_gms_fail_ok, ((dialog1, which1) -> { + + })) + .setNegativeButton(android.R.string.cancel, null) + .create(); + showDialog(failDialog); + }); + + } + }); + })) + .setNegativeButton(android.R.string.cancel, null) + .create(); + + showDialog(alertDialog); + } + + + private static void showDialog(AlertDialog dialog) { + if (dialog == null) { + return; + } + try { + dialog.show(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private static String installGmsInternal(Activity activity, ProgressDialog dialog) { + File cacheDir = activity.getCacheDir(); + + // 下载配置文件,得到各自的URL + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build(); + + Request request = new Request.Builder() + .url(GMS_CONFIG_URL) + .build(); + + updateMessage(activity, dialog, "Fetching gms config..."); + Response response; + try { + response = client.newCall(request).execute(); + } catch (IOException e) { + return "Download gms config failed, please check your network, error: 0"; + } + + if (!response.isSuccessful()) { + return "Download gms config failed, please check your network, error: 1"; + } + + Log.i(TAG, "response success: " + response.code()); + if (200 != response.code()) { + return "Download gms config failed, please check your network, error: 2"; + } + + updateMessage(activity, dialog, "Parsing gms config..."); + ResponseBody body = response.body(); + if (body == null) { + return "Download gms config failed, please check your network, error: 3"; + } + + String string = null; + try { + string = body.string(); + } catch (IOException e) { + return "Download gms config failed, please check your network, error: 4"; + } + + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(string); + } catch (JSONException e) { + return "Download gms config failed, please check your network, error: 5"; + } + String gmsCoreUrl = null; + try { + gmsCoreUrl = jsonObject.getString("gms"); + } catch (JSONException e) { + return "Download gms config failed, please check your network, error: 6"; + } + String gmsServiceUrl = null; + try { + gmsServiceUrl = jsonObject.getString("gsf"); + } catch (JSONException e) { + return "Download gms config failed, please check your network, error: 7"; + } + String storeUrl = null; + try { + storeUrl = jsonObject.getString("store"); + } catch (JSONException e) { + return "Download gms config failed, please check your network, error: 8"; + } + String fakeGappsUrl = null; + try { + fakeGappsUrl = jsonObject.getString("fakegapps"); + } catch (JSONException e) { + return "Download gms config failed, please check your network, error: 9"; + } + + updateMessage(activity, dialog, "config parse success!"); + + File gmsCoreFile = new File(cacheDir, "gms.apk"); + File gmsServiceFile = new File(cacheDir, "gsf.apk"); + File storeFile = new File(cacheDir, "store.apk"); + File fakeGappsFile = new File(cacheDir, "fakegapps.apk"); + + // clear old files. + if (gmsCoreFile.exists()) { + gmsCoreFile.delete(); + } + if (gmsServiceFile.exists()) { + gmsServiceFile.delete(); + } + if (storeFile.exists()) { + storeFile.delete(); + } + if (fakeGappsFile.exists()) { + fakeGappsFile.delete(); + } + + boolean downloadResult = downloadFile(gmsCoreUrl, gmsCoreFile, + (progress) -> updateMessage(activity, dialog, "download gms core..." + progress + "%")); + if (!downloadResult) { + return "Download gms config failed, please check your network, error: 10"; + } + + downloadResult = downloadFile(gmsServiceUrl, gmsServiceFile, + (progress -> updateMessage(activity, dialog, "download gms service framework proxy.." + progress + "%"))); + + if (!downloadResult) { + return "Download gms config failed, please check your network, error: 11"; + } + + updateMessage(activity, dialog, "download gms store..."); + + downloadResult = downloadFile(storeUrl, storeFile, + (progress -> updateMessage(activity, dialog, "download gms store.." + progress + "%"))); + if (!downloadResult) { + return "Download gms config failed, please check your network, error: 12"; + } + + downloadResult = downloadFile(fakeGappsUrl, fakeGappsFile, + (progress -> updateMessage(activity, dialog, "download gms Xposed module.." + progress + "%"))); + if (!downloadResult) { + return "Download gms config failed, please check your network, error: 13"; + } + + updateMessage(activity, dialog, "installing gms core"); + InstallResult installResult = VirtualCore.get().installPackage(gmsCoreFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST); + + if (!installResult.isSuccess) { + return "install gms core failed: " + installResult.error; + } + + updateMessage(activity, dialog, "installing gms service framework..."); + installResult = VirtualCore.get().installPackage(gmsServiceFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST); + if (!installResult.isSuccess) { + return "install gms service framework failed: " + installResult.error; + } + + updateMessage(activity, dialog, "installing gms store..."); + installResult = VirtualCore.get().installPackage(storeFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST); + if (!installResult.isSuccess) { + return "install gms store failed: " + installResult.error; + } + + updateMessage(activity, dialog, "installing gms Xposed module..."); + installResult = VirtualCore.get().installPackage(fakeGappsFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST); + if (!installResult.isSuccess) { + return "install gms xposed module failed: " + installResult.error; + } + + // Enable the Xposed module. + File dataDir = VEnvironment.getDataUserPackageDirectory(0, "de.robv.android.xposed.installer"); + File configDir = new File(dataDir, "exposed_conf" + File.separator + "modules.list"); + FileWriter writer = null; + try { + writer = new FileWriter(configDir, true); + writer.append('\n'); + writer.append("com.thermatk.android.xf.fakegapps.FakeSignatures"); + writer.append('\n'); + writer.append("com.thermatk.android.xf.fakegapps.PackageNameServiceHook"); + writer.flush(); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + // success!!! + return null; + } + + private static void updateMessage(Activity activity, ProgressDialog dialog, String msg) { + if (activity == null || dialog == null || TextUtils.isEmpty(msg)) { + return; + } + Log.i(TAG, "update dialog message: " + msg); + activity.runOnUiThread(() -> { + dialog.setMessage(msg); + }); + } + + interface DownloadListener { + void onProgress(int progress); + } + + private static boolean downloadFile(String url, File outFile, DownloadListener listener) { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder().url(url).build(); + FileOutputStream fos = null; + try { + Response response = client.newCall(request).execute(); + if (response.code() != 200) { + return false; + } + ResponseBody body = response.body(); + if (body == null) { + return false; + } + long toal = body.contentLength(); + long sum = 0; + + InputStream inputStream = body.byteStream(); + fos = new FileOutputStream(outFile); + byte[] buffer = new byte[1024]; + int count = 0; + while ((count = inputStream.read(buffer)) >= 0) { + fos.write(buffer, 0, count); + sum += count; + int progress = (int) ((sum * 1.0) / toal * 100); + if (listener != null) { + listener.onProgress(progress); + } + } + fos.flush(); + return true; + } catch (IOException e) { + return false; + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } + + private static void showFailTips(Activity activity) { + + } + +} diff --git a/VirtualApp/app/src/main/java/io/virtualapp/settings/SettingsActivity.java b/VirtualApp/app/src/main/java/io/virtualapp/settings/SettingsActivity.java index e09928440..0161526b4 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/settings/SettingsActivity.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/settings/SettingsActivity.java @@ -29,6 +29,7 @@ import io.virtualapp.R; import io.virtualapp.abs.ui.VUiKit; +import io.virtualapp.gms.FakeGms; import io.virtualapp.home.ListAppActivity; import moe.feng.alipay.zerosdk.AlipayZeroSdk; @@ -211,27 +212,16 @@ public void onCreate(Bundle savedInstanceState) { } }); - /* - SwitchPreference installGms = (SwitchPreference) findPreference(INSTALL_GMS_KEY); - installGms.setOnPreferenceChangeListener(((preference, newValue) -> { - if (!(newValue instanceof Boolean)) { - return false; - } - boolean install = (boolean) newValue; - if (install) { - if (!GmsSupport.isOutsideGoogleFrameworkExist()) { - Toast.makeText(getActivity(), "Sorry, your phone has no GMS supported.", Toast.LENGTH_SHORT).show(); - return false; - } - - Toast.makeText(getActivity(), "Coming soon.", Toast.LENGTH_SHORT).show(); - // Installd.addGmsSupport(); - return false; + Preference installGms = findPreference(INSTALL_GMS_KEY); + installGms.setOnPreferenceClickListener(preference -> { + boolean alreadyInstalled = FakeGms.isAlreadyInstalled(getActivity()); + if (alreadyInstalled) { + FakeGms.uninstallGms(getActivity()); } else { - // TODO, delete. + FakeGms.installGms(getActivity()); } - return false; - }));*/ + return true; + }); copyFile.setOnPreferenceClickListener((preference -> { Context context = getActivity(); diff --git a/VirtualApp/app/src/main/res/values-es/strings.xml b/VirtualApp/app/src/main/res/values-es/strings.xml index ed77bfa1a..a9c64e313 100644 --- a/VirtualApp/app/src/main/res/values-es/strings.xml +++ b/VirtualApp/app/src/main/res/values-es/strings.xml @@ -126,7 +126,7 @@ Retornar al lanzador del sistema en vez del lanzador vitual cuando se está en una aplicación virtualizada.\n(Reiniciar VirtualXposed para que los cambios surtan efecto) Chico, tu idea es prometedora :) Grupo de Telegram: %1$s - Instalar Servicios de Google + Instalar / Desinstalar servicios de Google Copiar archivo Activar esta opción para un balance entre estabilidad y compatibilidad Modo conservativo @@ -147,4 +147,15 @@ Aplicación: %1$s no concede el permiso necesario, no se puede iniciar. Dirígete a la administración de permisos de tu dispositivo y dale permisos. Lanzamiento fallido Si desea instalar apk desde el almacenamiento externo, dele el permiso a VirtualXposed. + + El servicio de Google es compatible con microG, VirtualXposed está a punto de descargar un archivo (2M) y puede consumir más batería, ¿le gustaría instalarlo? + Instalación fallida + Instalar Google Service falló automáticamente, también puede instalarlo manualmente. + Manual de instalación + Desinstalar el servicio de Google + ¿Desea desinstalar el servicio de Google? puedes reinstalarlo más tarde. + Desinstalar, confirmar + El servicio de Google ha sido instalado. + ¡El servicio de Google se ha instalado con éxito! + El servicio de Google ha sido desinstalado con éxito. diff --git a/VirtualApp/app/src/main/res/values-fr/strings.xml b/VirtualApp/app/src/main/res/values-fr/strings.xml index 98c0e8b71..1ce5e5a6e 100644 --- a/VirtualApp/app/src/main/res/values-fr/strings.xml +++ b/VirtualApp/app/src/main/res/values-fr/strings.xml @@ -125,7 +125,7 @@ Directement en arrière Revenir au lanceur système au lieu du lanceur virtuel dans une application virtuelle.\n(Redémarrer VirtualXposed pour prendre en compte le changement.) Mec, Ton idée est prometteuse. :) - Installer Services Google + Installer / Désinstaller les services Google Group Telegram: %1$s Copier fichier Ouvrir ceci pour un compromis entre la stabilité et la compatibilité. @@ -147,4 +147,15 @@ App: %1$s n\'accorde pas l\'autorisation nécessaire, il ne peut pas être lancé. Veuillez accéder à la gestion des autorisations de votre appareil et lui accorder des autorisations. Le lancement a échoué. Si vous voulez installer apk à partir d\'un espace de stockage externe, veuillez donner à VirtualXposed la permission. + + Le service Google est pris en charge par microG, VirtualXposed est sur le point de télécharger un fichier (2M), et il peut consommer plus de batterie, souhaitez-vous l\'installer? + Installation échouée + L\'installation de Google Service a échoué automatiquement, vous pouvez également l\'installer manuellement. + Installation manuelle + Désinstaller le service Google + Voulez-vous désinstaller Google Service? vous pouvez le réinstaller plus tard. + Désinstaller, confirmer + Le service Google a été installé. + Le service Google a été installé avec succès !! + Le service Google a été désinstallé avec succès !! diff --git a/VirtualApp/app/src/main/res/values-ru/strings.xml b/VirtualApp/app/src/main/res/values-ru/strings.xml index d29794922..f70ef2368 100644 --- a/VirtualApp/app/src/main/res/values-ru/strings.xml +++ b/VirtualApp/app/src/main/res/values-ru/strings.xml @@ -167,4 +167,16 @@ Приложение: %1$s не предоставляет необходимое разрешение, его не запускать. Перейдите к управлению разрешения вашего устройства и дайте ему разрешения. Запуск завершился неудачно. Если вы хотите установить apk из внешнего хранилища, пожалуйста, дайте VirtualXposed разрешение. + + Служба Google поддерживается microG, VirtualXposed собирается загрузить некоторый файл (2M), и он может потреблять больше батареи, хотите ли вы его установить? + Ошибка установки + Устанавливать службу Google автоматически не удалось, вы также можете установить ее вручную. + Ручная установка + Удаление службы Google + Удалить службу Google? вы можете переустановить его позже. + Удалить, подтвердить + Служба Google установлена. + Служба Google установлена успешно! + Служба Google успешно удалена! + Installer / Désinstaller les services Google diff --git a/VirtualApp/app/src/main/res/values-zh-rCN/strings.xml b/VirtualApp/app/src/main/res/values-zh-rCN/strings.xml index bb62460ef..7eb297f57 100644 --- a/VirtualApp/app/src/main/res/values-zh-rCN/strings.xml +++ b/VirtualApp/app/src/main/res/values-zh-rCN/strings.xml @@ -121,7 +121,7 @@ 直接返回 内部APP退出时,直接返回到系统桌面而不是VirtualXposed的虚拟桌面(强制停止VirtualXposed后生效) 小伙子,你这个想法很有前途 :) - 安装Google服务框架 + 安装/移除Google服务 Telegram 群组: %1$s 内部文件复制 开启这个开关,可能会提高VirtualXposed的稳定性,但同时会失去对插件的一些兼容性。 @@ -143,4 +143,14 @@ %1$s 没有获取到某些运行必须要使用的权限;它不支持动态申请权限. 请去您设备的系统权限管理中赋予 VirtualXposed 必要权限。 启动失败 如果你想把SD中的APK安装到 VirtualXposed,请赋予它外部存储权限。 + 安装Google服务 + Google 服务是通过 micorG 支持的,需要下载 2M 左右的文件,安装完之后耗电量可能会增加,确认需要安装吗? + 安装失败 + 自动安装Google 服务失败,你可以参考教程手动安装。 + 查看教程 + 移除Google服务 + 确定要移除 Google 服务吗?需要的时候你可以重新安装它。 + 确认移除 + Google 服务已经安装成功!! + Google服务已经移除成功!! diff --git a/VirtualApp/app/src/main/res/values/strings.xml b/VirtualApp/app/src/main/res/values/strings.xml index 2f2684558..d54ebf26d 100644 --- a/VirtualApp/app/src/main/res/values/strings.xml +++ b/VirtualApp/app/src/main/res/values/strings.xml @@ -126,7 +126,7 @@ Directly back Go back to the system launcher instead of the virtual launcher when in a virtual app.\n(Restart VirtualXposed to take effect.) Boy, your idea is promising :) - Install Google Services + Install/Uninstall Google Services Telegram Group: %1$s Copy File Open this for a trade-off between stability and compatibility. @@ -149,4 +149,15 @@ App: %1$s doesn\'t grant necessary permission, it cann\'t be launched. Please go to your device\'s permission management and give it permissions. Launch failed. If you want to install apk from external storage, please give VirtualXposed the permission. + Install Google Service + The Google Service is supported by microG, VirtualXposed is about to download some file(2M), and it may consume more battery, would you like to install it? + Install failed + Install Google Service automatically failed, you can also install it manually. + Manual Install + Uninstall Google Service + Would you like to uninstall Google Service? you can reinstall it later. + Uninstall, Confirm + The Google Service has been installed. + Google Service has been installed successfully!! + Google Service has been uninstalled successfully!! diff --git a/VirtualApp/app/src/main/res/xml/settings_preferences.xml b/VirtualApp/app/src/main/res/xml/settings_preferences.xml index 4ddf3c723..03a215319 100644 --- a/VirtualApp/app/src/main/res/xml/settings_preferences.xml +++ b/VirtualApp/app/src/main/res/xml/settings_preferences.xml @@ -22,12 +22,10 @@ android:key="settings_advance" android:title="@string/settings_advance"> - - - - - - +