mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-05 18:25:31 +08:00
Added: Add support for plugin apps to set TERMUX_APP_PACKAGE_VARIANT and TERMUX_APP_PACKAGE_MANAGER from Termux app APK BuildConfig.TERMUX_PACKAGE_VARIANT
This commit is contained in:
@@ -77,6 +77,8 @@ public class ReflectionUtils {
|
||||
/**
|
||||
* Get a value for a {@link Field} of an object for the specified class.
|
||||
*
|
||||
* Trying to access {@code null} fields will result in {@link NoSuchFieldException}.
|
||||
*
|
||||
* @param clazz The {@link Class} to which the object belongs to.
|
||||
* @param fieldName The name of the {@link Field}.
|
||||
* @param object The {@link Object} instance from which to get the field value.
|
||||
|
@@ -1,20 +1,29 @@
|
||||
package com.termux.shared.termux;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.termux.TermuxConstants.TERMUX_APP;
|
||||
|
||||
public class TermuxBootstrap {
|
||||
|
||||
private static final String LOG_TAG = "TermuxBootstrap";
|
||||
|
||||
/** The field name used by Termux app to store package variant in
|
||||
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class. */
|
||||
public static final String BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT = "TERMUX_PACKAGE_VARIANT";
|
||||
|
||||
|
||||
/** The {@link PackageManager} for the bootstrap in the app APK added in app/build.gradle. */
|
||||
public static PackageManager TERMUX_APP_PACKAGE_MANAGER;
|
||||
|
||||
/** The {@link PackageVariant} for the bootstrap in the app APK added in app/build.gradle. */
|
||||
public static PackageVariant TERMUX_APP_PACKAGE_VARIANT;
|
||||
|
||||
/** Set name as app wide night mode value. */
|
||||
/** Set {@link #TERMUX_APP_PACKAGE_VARIANT} and {@link #TERMUX_APP_PACKAGE_MANAGER} from {@code packageVariantName} passed. */
|
||||
public static void setTermuxPackageManagerAndVariant(@Nullable String packageVariantName) {
|
||||
TERMUX_APP_PACKAGE_VARIANT = PackageVariant.variantOf(packageVariantName);
|
||||
if (TERMUX_APP_PACKAGE_VARIANT == null) {
|
||||
@@ -34,6 +43,42 @@ public class TermuxBootstrap {
|
||||
Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_MANAGER to \"" + TERMUX_APP_PACKAGE_MANAGER + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link #TERMUX_APP_PACKAGE_VARIANT} and {@link #TERMUX_APP_PACKAGE_MANAGER} with the
|
||||
* {@link #BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT} field value from the
|
||||
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app APK installed on the device.
|
||||
* This can only be used by apps that share `sharedUserId` with the Termux app and can be used
|
||||
* by plugin apps.
|
||||
*
|
||||
* @param currentPackageContext The context of current package.
|
||||
*/
|
||||
public static void setTermuxPackageManagerAndVariantFromTermuxApp(@NonNull Context currentPackageContext) {
|
||||
String packageVariantName = getTermuxAppBuildConfigPackageVariantFromTermuxApp(currentPackageContext);
|
||||
if (packageVariantName != null) {
|
||||
TermuxBootstrap.setTermuxPackageManagerAndVariant(packageVariantName);
|
||||
} else {
|
||||
Logger.logError(LOG_TAG, "Failed to set TERMUX_APP_PACKAGE_VARIANT and TERMUX_APP_PACKAGE_MANAGER from the termux app");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link #BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT} field value from the
|
||||
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app APK installed on the device.
|
||||
* This can only be used by apps that share `sharedUserId` with the Termux app.
|
||||
*
|
||||
* @param currentPackageContext The context of current package.
|
||||
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
|
||||
* to get termux app package context.
|
||||
*/
|
||||
public static String getTermuxAppBuildConfigPackageVariantFromTermuxApp(@NonNull Context currentPackageContext) {
|
||||
try {
|
||||
return (String) TermuxUtils.getTermuxAppAPKBuildConfigClassField(currentPackageContext, BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT);
|
||||
} catch (Exception e) {
|
||||
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT + "\" value from \"" + TERMUX_APP.BUILD_CONFIG_CLASS_NAME + "\" class", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Is {@link PackageManager#APT} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */
|
||||
|
@@ -11,7 +11,7 @@ import java.util.Formatter;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Version: v0.44.0
|
||||
* Version: v0.45.0
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Changelog
|
||||
@@ -248,6 +248,9 @@ import java.util.List;
|
||||
*
|
||||
* - 0.44.0 (2022-05-29)
|
||||
* - Changed `TERMUX_APP.APPS_DIR_PATH` basename from `termux-app` to `com.termux`.
|
||||
*
|
||||
* - 0.45.0 (2022-06-01)
|
||||
* - Added `TERMUX_APP.BUILD_CONFIG_CLASS_NAME`.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -904,6 +907,9 @@ public final class TermuxConstants {
|
||||
/** termux-am socket file path */
|
||||
public static final String TERMUX_AM_SOCKET_FILE_PATH = APPS_DIR_PATH + "/termux-am/am.sock"; // Default: "/data/data/com.termux/files/apps/com.termux/termux-am/am.sock"
|
||||
|
||||
/** Termux app BuildConfig class name */
|
||||
public static final String BUILD_CONFIG_CLASS_NAME = TERMUX_PACKAGE_NAME + ".BuildConfig"; // Default: "com.termux.BuildConfig"
|
||||
|
||||
|
||||
/** Termux app core activity name. */
|
||||
public static final String TERMUX_ACTIVITY_NAME = TERMUX_PACKAGE_NAME + ".app.TermuxActivity"; // Default: "com.termux.app.TermuxActivity"
|
||||
|
@@ -14,6 +14,7 @@ import com.termux.shared.R;
|
||||
import com.termux.shared.android.AndroidUtils;
|
||||
import com.termux.shared.data.DataUtils;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.reflection.ReflectionUtils;
|
||||
import com.termux.shared.shell.command.runner.app.AppShell;
|
||||
import com.termux.shared.termux.file.TermuxFileUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
@@ -21,6 +22,7 @@ import com.termux.shared.markdown.MarkdownUtils;
|
||||
import com.termux.shared.shell.command.ExecutionCommand;
|
||||
import com.termux.shared.errors.Error;
|
||||
import com.termux.shared.android.PackageUtils;
|
||||
import com.termux.shared.termux.TermuxConstants.TERMUX_APP;
|
||||
import com.termux.shared.termux.shell.TermuxShellEnvironmentClient;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -218,6 +220,59 @@ public class TermuxUtils {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get a field value from the {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app
|
||||
* APK installed on the device.
|
||||
* This can only be used by apps that share `sharedUserId` with the Termux app.
|
||||
*
|
||||
* This is a wrapper for {@link #getTermuxAppAPKClassField(Context, String, String)}.
|
||||
*
|
||||
* @param currentPackageContext The context of current package.
|
||||
* @param fieldName The name of the field to get.
|
||||
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
|
||||
* to get termux app package context.
|
||||
*/
|
||||
public static Object getTermuxAppAPKBuildConfigClassField(@NonNull Context currentPackageContext,
|
||||
@NonNull String fieldName) {
|
||||
return getTermuxAppAPKClassField(currentPackageContext, TERMUX_APP.BUILD_CONFIG_CLASS_NAME, fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field value from a class of the Termux app APK installed on the device.
|
||||
* This can only be used by apps that share `sharedUserId` with the Termux app.
|
||||
*
|
||||
* This is done by getting first getting termux app package context and then getting in class
|
||||
* loader (instead of current app's) that contains termux app class info, and then using that to
|
||||
* load the required class and then getting required field from it.
|
||||
*
|
||||
* Note that the value returned is from the APK file and not the current value loaded in Termux
|
||||
* app process, so only default values will be returned.
|
||||
*
|
||||
* Trying to access {@code null} fields will result in {@link NoSuchFieldException}.
|
||||
*
|
||||
* @param currentPackageContext The context of current package.
|
||||
* @param clazzName The name of the class from which to get the field.
|
||||
* @param fieldName The name of the field to get.
|
||||
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
|
||||
* to get termux app package context.
|
||||
*/
|
||||
public static Object getTermuxAppAPKClassField(@NonNull Context currentPackageContext,
|
||||
@NonNull String clazzName, @NonNull String fieldName) {
|
||||
try {
|
||||
Context termuxPackageContext = TermuxUtils.getTermuxPackageContextWithCode(currentPackageContext);
|
||||
if (termuxPackageContext == null)
|
||||
return null;
|
||||
|
||||
Class<?> clazz = termuxPackageContext.getClassLoader().loadClass(clazzName);
|
||||
return ReflectionUtils.invokeField(clazz, fieldName, null).value;
|
||||
} catch (Exception e) {
|
||||
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + fieldName + "\" value from \"" + clazzName + "\" class", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux
|
||||
* app has been opened.
|
||||
|
Reference in New Issue
Block a user