diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 597a36ac..773207e1 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -14,6 +14,7 @@ "精简打包应用模板 APK 文件大小", "打包页面支持 Pinyin 库选项", "打包应用主活动页面优化状态栏背景及文字颜色", + "脚本项目配置文件 project.json 支持更多打包选项 _[`issue #305`](http://issues.autojs6.com/305)_ _[`issue #306`](http://issues.autojs6.com/306)_", "APK 文件类型信息对话框增加文件大小与签名方案信息", "APK 文件类型信息对话框增加点击监听器支持文本复制与应用详情跳转", "尝试恢复 com.stardust 前缀包以便提升代码兼容性 _[`issue #290`](http://issues.autojs6.com/290)_", diff --git a/app/src/main/java/org/autojs/autojs/annotation/SerializedNameCompatible.kt b/app/src/main/java/org/autojs/autojs/annotation/SerializedNameCompatible.kt new file mode 100644 index 00000000..411978a5 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/annotation/SerializedNameCompatible.kt @@ -0,0 +1,7 @@ +package org.autojs.autojs.annotation + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.FUNCTION) +annotation class SerializedNameCompatible(vararg val with: With) { + annotation class With(val value: String, val target: Array = ["AutoJs6"], val isReversed: Boolean = false) +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt index 8bb8a4b7..4b9d2a95 100644 --- a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt +++ b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt @@ -5,7 +5,6 @@ import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES import android.content.res.AssetManager import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.os.Build import android.util.Log import com.mcal.apksigner.ApkSigner @@ -13,7 +12,6 @@ import com.reandroid.arsc.chunk.TableBlock import org.apache.commons.io.FileUtils.copyFile import org.apache.commons.io.FileUtils.copyInputStreamToFile import org.autojs.autojs.apkbuilder.keystore.AESUtils -import org.autojs.autojs.apkbuilder.keystore.KeyStore import org.autojs.autojs.app.GlobalAppContext import org.autojs.autojs.engine.encryption.AdvancedEncryptionStandard import org.autojs.autojs.pio.PFiles @@ -35,7 +33,6 @@ import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException import java.io.InputStream -import java.util.concurrent.Callable /** * Created by Stardust on Oct 24, 2017. @@ -49,7 +46,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File private var mInitVector: String? = null private var mKey: String? = null - private lateinit var mAppConfig: AppConfig + private lateinit var mProjectConfig: ProjectConfig private val mApkPackager = ApkPackager(apkInputStream, workspacePath) @@ -59,6 +56,9 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File private var mAssetsFileIncludes = Libs.defaultAssetFilesToInclude.toMutableList() private var mAssetsDirExcludes = Libs.defaultAssetDirsToExclude.toMutableList() + private var mSplashThemeId = 0 + private var mNoSplashThemeId = 0 + private val mManifestFile get() = File(workspacePath, "AndroidManifest.xml") @@ -105,7 +105,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File srcChildFile.copyTo(File(destDirFile, srcChildFile.name), true) } } else { - if (!mAppConfig.ignoredDirs.contains(srcChildFile)) { + if (!mProjectConfig.ignoredDirs.contains(srcChildFile)) { copyDir(srcChildFile, PFiles.join(relativeDestPath, srcChildFile.name + File.separator)) } } @@ -141,10 +141,27 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File } @Throws(IOException::class) - fun withConfig(config: AppConfig) = also { - config.also { mAppConfig = it }.run { + fun withConfig(config: ProjectConfig) = also { + config.also { mProjectConfig = it }.run { + if (!launchConfig.isSplashVisible) { + try { + val tableBlock = TableBlock.load(mResourcesArscFile) + val packageName = "${GlobalAppContext.get().packageName}.inrt" + val packageBlock = tableBlock.getOrCreatePackage(0x7f, packageName).also { + tableBlock.currentPackage = it + } + packageBlock.getEntry("", "style", "AppTheme.Splash")?.let { + mSplashThemeId = it.resourceId + } + packageBlock.getEntry("", "style", "AppTheme.SevereTransparent")?.let { + mNoSplashThemeId = it.resourceId + } + } catch (e: Exception) { + e.printStackTrace() + } + } mManifestEditor = editManifest() - .setAppName(appName) + .setAppName(name) .setVersionName(versionName) .setVersionCode(versionCode) .setPackageName(packageName) @@ -160,32 +177,32 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File @Throws(FileNotFoundException::class) fun editManifest(): ManifestEditor = ManifestEditorWithAuthorities(FileInputStream(mManifestFile)).also { mManifestEditor = it } - private fun updateProjectConfig(appConfig: AppConfig) { + private fun updateProjectConfig(config: ProjectConfig) { val projectConfig = when { - !PFiles.isDir(appConfig.sourcePath) -> null - else -> ProjectConfig.fromProjectDir(appConfig.sourcePath)?.also { + !PFiles.isDir(config.sourcePath) -> null + else -> ProjectConfig.fromProjectDir(config.sourcePath)?.also { val buildNumber = it.buildInfo.buildNumber it.buildInfo = BuildInfo.generate(buildNumber + 1) - PFiles.write(ProjectConfig.configFileOfDir(appConfig.sourcePath), it.toJson()) + PFiles.write(ProjectConfig.configFileOfDir(config.sourcePath), it.toJson()) } } ?: ProjectConfig() .setMainScriptFile("main.js") - .setName(appConfig.appName) - .setPackageName(appConfig.packageName) - .setVersionName(appConfig.versionName) - .setVersionCode(appConfig.versionCode) - .also { config -> - config.buildInfo = BuildInfo.generate(appConfig.versionCode.toLong()) + .setName(config.name) + .setPackageName(config.packageName) + .setVersionName(config.versionName) + .setVersionCode(config.versionCode) + .also { newProjectConfig -> + newProjectConfig.buildInfo = BuildInfo.generate(newProjectConfig.versionCode.toLong()) File(workspacePath, "assets/project/${ProjectConfig.CONFIG_FILE_NAME}").also { file -> file.parentFile?.let { parent -> if (!parent.exists()) parent.mkdirs() } - }.writeText(config.toJson()) + }.writeText(newProjectConfig.toJson()) } projectConfig.run { mKey = MD5Utils.md5(packageName + versionName + mainScriptFile) mInitVector = MD5Utils.md5(buildInfo.buildId + name).substring(0, 16) Libs.entries.forEach { entry -> - if (appConfig.libs.contains(entry.label)) { + if (config.libs.contains(entry.label)) { mLibsIncludes += entry.libsToInclude.toSet() mAssetsFileIncludes += entry.assetFilesToInclude.toSet() mAssetsDirExcludes -= entry.assetDirsToExclude.toSet() @@ -197,7 +214,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File @Throws(Exception::class) fun build() = also { mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onBuild(this) } } - mAppConfig.icon?.let { callable -> + mProjectConfig.iconBitmapGetter?.let { callable -> runCatching { val tableBlock = TableBlock.load(mResourcesArscFile) val packageName = "${GlobalAppContext.get().packageName}.inrt" @@ -264,17 +281,17 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File val signer = ApkSigner(outApkFile, tmpOutputApk) signer.useDefaultSignatureVersion = false - signer.v1SigningEnabled = mAppConfig.signatureSchemes.contains("V1") - signer.v2SigningEnabled = mAppConfig.signatureSchemes.contains("V2") - signer.v3SigningEnabled = mAppConfig.signatureSchemes.contains("V3") - signer.v4SigningEnabled = mAppConfig.signatureSchemes.contains("V4") + signer.v1SigningEnabled = mProjectConfig.signatureSchemes.contains("V1") + signer.v2SigningEnabled = mProjectConfig.signatureSchemes.contains("V2") + signer.v3SigningEnabled = mProjectConfig.signatureSchemes.contains("V3") + signer.v4SigningEnabled = mProjectConfig.signatureSchemes.contains("V4") var keyStoreFile = defaultKeyStoreFile var password = "AutoJs6" var alias = "AutoJs6" var aliasPassword = "AutoJs6" - mAppConfig.keyStore?.let { + mProjectConfig.keyStore?.let { keyStoreFile = File(it.absolutePath) password = AESUtils.decrypt(it.password) alias = it.alias @@ -324,76 +341,14 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File } - class AppConfig { - - var appName: String? = null - private set - var versionName: String? = null - private set - var versionCode = 0 - private set - var sourcePath: String? = null - private set - var packageName: String? = null - private set - var ignoredDirs = ArrayList() - var icon: Callable? = null - private set - var abis: List = emptyList() - private set - var libs: List = emptyList() - private set - var keyStore: KeyStore? = null - private set - var signatureSchemes: String = "V1 + V2" - private set - var permissions: List = emptyList() - private set - - fun ignoreDir(dir: File) = also { ignoredDirs.add(dir) } - - fun setAppName(appName: String?) = also { appName?.let { this.appName = it } } - - fun setVersionName(versionName: String?) = also { versionName?.let { this.versionName = it } } - - fun setVersionCode(versionCode: Int?) = also { versionCode?.let { this.versionCode = it } } - - fun setSourcePath(sourcePath: String?) = also { sourcePath?.let { this.sourcePath = it } } - - fun setPackageName(packageName: String?) = also { packageName?.let { this.packageName = it } } - - fun setIcon(icon: Callable?) = also { icon?.let { this.icon = it } } - - fun setIcon(iconPath: String?) = also { iconPath?.let { this.icon = Callable { BitmapFactory.decodeFile(it) } } } - - fun setAbis(abis: List) = also { this.abis = abis } - - fun setLibs(libs: List) = also { this.libs = libs } - - fun setKeyStore(keyStore: KeyStore?) = also { this.keyStore = keyStore } - - fun setSignatureSchemes(signatureSchemes: String) = also { this.signatureSchemes = signatureSchemes } - - fun setPermissions(permissions: List) = also { this.permissions = permissions } - - companion object { - @JvmStatic - fun fromProjectConfig(projectDir: String?, projectConfig: ProjectConfig) = AppConfig() - .setAppName(projectConfig.name) - .setPackageName(projectConfig.packageName) - .ignoreDir(File(projectDir, projectConfig.buildDir)) - .setVersionCode(projectConfig.versionCode) - .setVersionName(projectConfig.versionName) - .setSourcePath(projectDir) - .setIcon(projectConfig.icon?.let { File(projectDir, it).path }) - } - } - private inner class ManifestEditorWithAuthorities(manifestInputStream: InputStream?) : ManifestEditor(manifestInputStream) { override fun onAttr(attr: AxmlWriter.Attr) { attr.apply { + if (!mProjectConfig.launchConfig.isSplashVisible && mSplashThemeId != 0 && value == mSplashThemeId) { + value = mNoSplashThemeId + } if (name.data == "authorities" && value is StringItem) { - (value as StringItem).data = "${mAppConfig.packageName}.fileprovider" + (value as StringItem).data = "${mProjectConfig.packageName}.fileprovider" } else { super.onAttr(this) } @@ -401,11 +356,11 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File } override fun isPermissionRequired(permissionName: String): Boolean { - return mAppConfig.permissions.contains(permissionName) + return mProjectConfig.permissions.contains(permissionName) } } - private fun copyLibrariesByConfig(config: AppConfig) { + private fun copyLibrariesByConfig(config: ProjectConfig) { // @Hint by SuperMonster003 on Dec 11, 2023. // ! The list contains only abi names not matching the canonical name itself. @@ -461,6 +416,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File } + @Suppress("SpellCheckingInspection") enum class Libs( @JvmField val label: String, @JvmField val aliases: List = emptyList(), diff --git a/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt index 68312ff1..beb0eacc 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt @@ -10,10 +10,11 @@ import android.os.Handler import android.os.Looper import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import org.autojs.autojs.inrt.autojs.AutoJs import org.autojs.autojs.inrt.launch.GlobalProjectLauncher +import org.autojs.autojs.project.ProjectConfig import org.autojs.autojs.ui.splash.SplashActivity.Companion.INIT_TIMEOUT -import org.autojs.autojs6.R import org.autojs.autojs6.databinding.ActivitySplashInrtBinding import kotlin.concurrent.thread @@ -24,14 +25,29 @@ import kotlin.concurrent.thread class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - setContentView(R.layout.activity_splash_inrt) - val binding = ActivitySplashInrtBinding.inflate(layoutInflater) - binding.slug.typeface = Typeface.createFromAsset(assets, "roboto_medium.ttf") + val binding = ActivitySplashInrtBinding.inflate(layoutInflater).apply { + setContentView(root) + } + val handler = Handler(Looper.myLooper()!!) + val projectConfig = ProjectConfig.fromAssets(this, ProjectConfig.configFileOfDir("project")) + var timeout = INIT_TIMEOUT + + if (!projectConfig.launchConfig.isSplashVisible) { + timeout = 0L + } else { + handler.post { + binding.slug.typeface = Typeface.createFromAsset(assets, "roboto_medium.ttf") + binding.slug.isVisible = true + binding.icon.isVisible = true + } + } + if (!Pref.isFirstUsing) { main() } else { - Handler(Looper.myLooper()!!).postDelayed({ this@SplashActivity.main() }, INIT_TIMEOUT) + handler.postDelayed({ this@SplashActivity.main() }, timeout) } + super.onCreate(savedInstanceState) } diff --git a/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt index 471e5235..8e8882ba 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt @@ -36,7 +36,7 @@ open class AssetsProjectLauncher(private val mAssetsProjectDir: String, private fun launch(activity: Activity) { // 如果需要隐藏日志界面, 则直接运行脚本 - if (mProjectConfig.launchConfig.shouldHideLogs() || Pref.shouldHideLogs()) { + if (!mProjectConfig.launchConfig.isLogsVisible || Pref.shouldHideLogs()) { runScript(activity) } else { // 如果不隐藏日志界面 diff --git a/app/src/main/java/org/autojs/autojs/project/BuildInfo.java b/app/src/main/java/org/autojs/autojs/project/BuildInfo.java index e53e7ab5..ca9e9687 100644 --- a/app/src/main/java/org/autojs/autojs/project/BuildInfo.java +++ b/app/src/main/java/org/autojs/autojs/project/BuildInfo.java @@ -6,13 +6,13 @@ import java.util.zip.CRC32; public class BuildInfo { - @SerializedName("build_time") + @SerializedName(value = "buildTime", alternate = {"build_time"}) private long mBuildTime; - @SerializedName("build_id") + @SerializedName(value = "buildId", alternate = {"build_id"}) private String mBuildId; - @SerializedName("build_number") + @SerializedName(value = "buildNumber", alternate = {"build_number"}) private long mBuildNumber; public long getBuildNumber() { diff --git a/app/src/main/java/org/autojs/autojs/project/LaunchConfig.kt b/app/src/main/java/org/autojs/autojs/project/LaunchConfig.kt index e3e8ead9..3c7b14e2 100644 --- a/app/src/main/java/org/autojs/autojs/project/LaunchConfig.kt +++ b/app/src/main/java/org/autojs/autojs/project/LaunchConfig.kt @@ -1,21 +1,57 @@ -package org.autojs.autojs.project; +package org.autojs.autojs.project -import com.google.gson.annotations.SerializedName; +import com.google.gson.annotations.SerializedName +import org.autojs.autojs.annotation.SerializedNameCompatible +import org.autojs.autojs.annotation.SerializedNameCompatible.With +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs6.R /** * Created by Stardust on Jan 25, 2018. + * Modified by SuperMonster003 as of Jan 15, 2025. + * Created by SuperMonster003 on Jan 15, 2025. */ -public class LaunchConfig { +class LaunchConfig { - @SerializedName("hideLogs") - private boolean mHideLogs = false; + @Transient + private val mContext = GlobalAppContext.get() - public boolean shouldHideLogs() { - return mHideLogs; - } + @SerializedName("logsVisible") + @field:SerializedNameCompatible( + With(value = "showLogs"), + With(value = "hideLogs", target = ["AutoJs4", "AutoX"], isReversed = true), + With(value = "displayLogs"), + ) + var isLogsVisible = true - public void setHideLogs(boolean hideLogs) { - mHideLogs = hideLogs; - } + @SerializedName("splashVisible") + @field:SerializedNameCompatible( + With(value = "showSplash"), + With(value = "hideSplash", isReversed = true), + With(value = "displaySplash", target = ["AutoX"]), + ) + var isSplashVisible = true + + @SerializedName("launcherVisible") + @field:SerializedNameCompatible( + With(value = "showLauncher"), + With(value = "hideLauncher", target = ["AutoX"], isReversed = true), + With(value = "displayLauncher"), + ) + var isLauncherVisible = true + + @SerializedName("slug") + @field:SerializedNameCompatible( + With(value = "slugText"), + With(value = "splashText", target = ["AutoX"]), + ) + var slug = mContext.getString(R.string.text_powered_by_autojs) + + @SerializedName("permissions") + @field:SerializedNameCompatible( + With(value = "permission"), + With(value = "permissionList"), + ) + var permissions = emptyList() } diff --git a/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java b/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java index cbe8c50a..01851bed 100644 --- a/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java +++ b/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java @@ -1,12 +1,15 @@ package org.autojs.autojs.project; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; +import org.autojs.autojs.apkbuilder.keystore.KeyStore; import org.autojs.autojs.model.explorer.ExplorerPage; import org.autojs.autojs.pio.PFiles; import org.autojs.autojs.util.JsonUtils; @@ -20,6 +23,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,7 +34,9 @@ public class ProjectConfig { public static final String CONFIG_FILE_NAME = "project.json"; - private static final Gson sGson = new GsonBuilder().setPrettyPrinting().create(); + private static final Gson sGson = new GsonBuilder() + .setPrettyPrinting() + .create(); @SerializedName("name") private String mName; @@ -52,13 +58,15 @@ public class ProjectConfig { private List mAssets = new ArrayList<>(); @SerializedName("launchConfig") - private LaunchConfig mLaunchConfig; + private LaunchConfig mLaunchConfig = new LaunchConfig(); @SerializedName("build") private BuildInfo mBuildInfo = new BuildInfo(); @SerializedName("icon") - private String mIcon; + private String mIconPath; + + private transient Callable mIconBitmapGetter; @Nullable @SerializedName(value = "abis", alternate = {"abi", "abiList"}) @@ -68,12 +76,27 @@ public class ProjectConfig { @SerializedName(value = "libs", alternate = {"lib", "libList"}) private List mLibs = new ArrayList<>(); + @SerializedName("permissions") + private List mPermissions = new ArrayList<>(); + + @SerializedName("signatureSchemes") + private String mSignatureSchemes = "V1 + V2"; + + @Nullable + private transient KeyStore mKeyStore = null; + @SerializedName("scripts") private final Map mScriptConfigs = new HashMap<>(); @SerializedName(value = "useFeatures", alternate = {"useFeature", "useFeatureList"}) private List mFeatures = new ArrayList<>(); + @SerializedName("ignoredDirs") + private final List mIgnoredDirs = new ArrayList<>(); + + @Nullable + private transient String mSourcePath = null; + public static ProjectConfig fromJson(String json) { if (json == null) { return null; @@ -117,7 +140,7 @@ public class ProjectConfig { return fromJson(fileContents); } catch (Exception e1) { if (fileContents == null) return null; - try { + try { return fromJson(JsonUtils.repairJson(fileContents)); } catch (Exception e2) { return tryReadCrucialData(fileContents, path); @@ -126,10 +149,9 @@ public class ProjectConfig { } private static ProjectConfig tryReadCrucialData(String s, String jsonFilePath) { - ProjectConfig config = new ProjectConfig(); - BuildInfo buildInfo = new BuildInfo(); - ScriptConfig scriptConfig = new ScriptConfig(); + ProjectConfig projectConfig = new ProjectConfig(); LaunchConfig launchConfig = new LaunchConfig(); + BuildInfo buildInfo = new BuildInfo(); Pattern namePattern = Pattern.compile(stringPattern("name")); Pattern versionNamePattern = Pattern.compile(stringPattern("versionName")); @@ -147,40 +169,47 @@ public class ProjectConfig { Pattern buildNumberPattern = Pattern.compile(numberPattern("buildNumber")); Pattern buildIdPattern = Pattern.compile(stringPattern("buildId")); - Pattern launchConfigPattern = Pattern.compile(booleanPattern("hideLogs")); + Pattern launchConfigHideLogsPattern = Pattern.compile(booleanPattern("hideLogs")); + Pattern launchConfigLogsVisiblePattern = Pattern.compile(booleanPattern("logsVisible")); - Pattern scriptsUiModePattern = Pattern.compile(booleanPattern("uiMode")); + Pattern launchConfigDisplaySplashPattern = Pattern.compile(booleanPattern("displaySplash")); + Pattern launchConfigSplashVisiblePattern = Pattern.compile(booleanPattern("splashVisible")); - setFieldIfMatches(namePattern, s, config::setName); - setFieldIfMatches(versionNamePattern, s, config::setVersionName); - setFieldForIntIfMatches(versionCodePattern, s, config::setVersionCode); - setFieldIfMatches(packageNamePattern, s, config::setPackageName); - setFieldIfMatches(mainPattern, s, config::setMainScriptFile); - setFieldIfMatches(iconPattern, s, config::setIcon); + setFieldIfMatches(namePattern, s, projectConfig::setName); + setFieldIfMatches(versionNamePattern, s, projectConfig::setVersionName); + setFieldForIntIfMatches(versionCodePattern, s, projectConfig::setVersionCode); + setFieldIfMatches(packageNamePattern, s, projectConfig::setPackageName); + setFieldIfMatches(mainPattern, s, projectConfig::setMainScriptFile); + setFieldIfMatches(iconPattern, s, projectConfig::setIconPath); - setListIfMatches(assetsPattern, s, config::setAssets); - setListIfMatches(abisPattern, s, config::setAbis); - setListIfMatches(libsPattern, s, config::setLibs); - setListIfMatches(useFeaturesPattern, s, config::setFeatures); + setListIfMatches(assetsPattern, s, projectConfig::setAssets); + setListIfMatches(abisPattern, s, projectConfig::setAbis); + setListIfMatches(libsPattern, s, projectConfig::setLibs); + setListIfMatches(useFeaturesPattern, s, projectConfig::setFeatures); setFieldForIntIfMatches(buildTimePattern, s, buildInfo::setBuildTime); setFieldForIntIfMatches(buildNumberPattern, s, buildInfo::setBuildNumber); setFieldIfMatches(buildIdPattern, s, buildInfo::setBuildId); - setFieldForBooleanIfMatches(launchConfigPattern, s, launchConfig::setHideLogs); + setFieldForBooleanIfMatches(launchConfigHideLogsPattern, s, value -> launchConfig.setLogsVisible(!value)); + setFieldForBooleanIfMatches(launchConfigLogsVisiblePattern, s, launchConfig::setLogsVisible); /* 优先. */ - setFieldForBooleanIfMatches(scriptsUiModePattern, s, scriptConfig::setUiMode); + setFieldForBooleanIfMatches(launchConfigDisplaySplashPattern, s, launchConfig::setSplashVisible); + setFieldForBooleanIfMatches(launchConfigSplashVisiblePattern, s, launchConfig::setSplashVisible); /* 优先. */ - if (config.getName() == null || config.getName().isBlank()) { + if (projectConfig.getName() == null || projectConfig.getName().isBlank()) { if (jsonFilePath.endsWith(CONFIG_FILE_NAME)) { File parentFile = new File(jsonFilePath).getParentFile(); if (parentFile != null) { - config.setName(parentFile.getName()); + projectConfig.setName(parentFile.getName()); } } } - return config; + projectConfig.setBuildInfo(buildInfo); + projectConfig.setLaunchConfig(launchConfig); + + return projectConfig; } @NotNull @@ -350,13 +379,10 @@ public class ProjectConfig { } public LaunchConfig getLaunchConfig() { - if (mLaunchConfig == null) { - mLaunchConfig = new LaunchConfig(); - } return mLaunchConfig; } - public void setLaunchConfig(LaunchConfig launchConfig) { + public void setLaunchConfig(@NonNull LaunchConfig launchConfig) { mLaunchConfig = launchConfig; } @@ -364,12 +390,23 @@ public class ProjectConfig { return sGson.toJson(this); } - public String getIcon() { - return mIcon; + public String getIconPath() { + return mIconPath; } - public void setIcon(String icon) { - mIcon = icon; + public ProjectConfig setIconPath(String iconPath) { + mIconPath = iconPath; + mIconBitmapGetter = () -> BitmapFactory.decodeFile(iconPath); + return this; + } + + public Callable getIconBitmapGetter() { + return mIconBitmapGetter; + } + + public ProjectConfig setIconGetter(@Nullable Callable getter) { + mIconBitmapGetter = getter; + return this; } public List getAbis() { @@ -379,8 +416,9 @@ public class ProjectConfig { return mAbis; } - public void setAbis(@Nullable List abis) { + public ProjectConfig setAbis(@Nullable List abis) { mAbis = abis; + return this; } public List getLibs() { @@ -390,8 +428,9 @@ public class ProjectConfig { return mLibs; } - public void setLibs(@Nullable List libs) { + public ProjectConfig setLibs(@Nullable List libs) { mLibs = libs; + return this; } public String getBuildDir() { @@ -427,4 +466,51 @@ public class ProjectConfig { config.setFeatures(features); return config; } + + public List getIgnoredDirs() { + return mIgnoredDirs; + } + + public ProjectConfig ignoredDir(File ignoredDir) { + mIgnoredDirs.add(ignoredDir); + return this; + } + + @Nullable + public String getSourcePath() { + return mSourcePath; + } + + public ProjectConfig setSourcePath(@Nullable String sourcePath) { + mSourcePath = sourcePath; + return this; + } + + public List getPermissions() { + return mPermissions; + } + + public ProjectConfig setPermissions(List permissions) { + mPermissions = permissions; + return this; + } + + public String getSignatureSchemes() { + return mSignatureSchemes; + } + + public ProjectConfig setSignatureSchemes(String signatureSchemes) { + mSignatureSchemes = signatureSchemes; + return this; + } + + @Nullable + public KeyStore getKeyStore() { + return mKeyStore; + } + + public ProjectConfig setKeyStore(@Nullable KeyStore keyStore) { + mKeyStore = keyStore; + return this; + } } diff --git a/app/src/main/java/org/autojs/autojs/project/ScriptConfig.kt b/app/src/main/java/org/autojs/autojs/project/ScriptConfig.kt index f83602e1..7fcd80ba 100644 --- a/app/src/main/java/org/autojs/autojs/project/ScriptConfig.kt +++ b/app/src/main/java/org/autojs/autojs/project/ScriptConfig.kt @@ -2,17 +2,14 @@ package org.autojs.autojs.project import com.google.gson.annotations.SerializedName -data class ScriptConfig( - @SerializedName("useFeatures") var features: List, - @SerializedName("uiMode") var uiMode: Boolean +data class ScriptConfig @JvmOverloads constructor( + @SerializedName("useFeatures") var features: List = emptyList(), ) { - constructor() : this(emptyList(), false) - fun hasFeature(feature: String): Boolean { - return features.contains(feature) - } + fun hasFeature(feature: String) = features.contains(feature) companion object { const val FEATURE_CONTINUATION = "continuation" } + } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java index 45f59230..53821d5f 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java @@ -160,18 +160,18 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa put("moe.shizuku.manager.permission.API_V23", R.string.text_permission_shizuku); }}; - EditText mSourcePath; - View mSourcePathContainer; - EditText mOutputPath; - EditText mAppName; - EditText mPackageName; - TextInputLayout mPackageNameParent; - EditText mVersionName; - TextInputLayout mVersionNameParent; - EditText mVersionCode; - TextInputLayout mVersionCodeParent; - ImageView mIcon; - LinearLayout mAppConfig; + EditText mSourcePathView; + View mSourcePathContainerView; + EditText mOutputPathView; + EditText mAppNameView; + EditText mPackageNameView; + TextInputLayout mPackageNameParentView; + EditText mVersionNameView; + TextInputLayout mVersionNameParentView; + EditText mVersionCodeView; + TextInputLayout mVersionCodeParentView; + ImageView mIconView; + LinearLayout mAppConfigView; private ProjectConfig mProjectConfig; private MaterialDialog mProgressDialog; @@ -209,24 +209,24 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa ActivityBuildBinding binding = ActivityBuildBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - mSourcePath = binding.sourcePath; - mSourcePath.setOnKeyListener((v, keyCode, event) -> { + mSourcePathView = binding.sourcePath; + mSourcePathView.setOnKeyListener((v, keyCode, event) -> { if (keyCode == KeyEvent.KEYCODE_ENTER) { if (event.getAction() == KeyEvent.ACTION_UP) { - mOutputPath.requestFocus(); + mOutputPathView.requestFocus(); } return true; } return false; }); - mSourcePathContainer = binding.sourcePathContainer; + mSourcePathContainerView = binding.sourcePathContainer; - mOutputPath = binding.outputPath; - mOutputPath.setOnKeyListener((v, keyCode, event) -> { + mOutputPathView = binding.outputPath; + mOutputPathView.setOnKeyListener((v, keyCode, event) -> { if (keyCode == KeyEvent.KEYCODE_ENTER) { if (event.getAction() == KeyEvent.ACTION_UP) { - TextView nextField = (TextView) mOutputPath.focusSearch(View.FOCUS_DOWN); + TextView nextField = (TextView) mOutputPathView.focusSearch(View.FOCUS_DOWN); if (nextField != null) { nextField.requestFocus(); } @@ -236,30 +236,30 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa return false; }); - mAppName = binding.appName; + mAppNameView = binding.appName; - mPackageName = binding.packageName; - mPackageName.setOnKeyListener((v, keyCode, event) -> { + mPackageNameView = binding.packageName; + mPackageNameView.setOnKeyListener((v, keyCode, event) -> { if (keyCode == KeyEvent.KEYCODE_ENTER) { if (event.getAction() == KeyEvent.ACTION_UP) { - mVersionName.requestFocus(); + mVersionNameView.requestFocus(); } return true; } return false; }); - mPackageNameParent = binding.packageNameParent; + mPackageNameParentView = binding.packageNameParent; - mVersionName = binding.versionName; - mVersionNameParent = binding.versionNameParent; - mVersionCode = binding.versionCode; - mVersionCodeParent = binding.versionCodeParent; + mVersionNameView = binding.versionName; + mVersionNameParentView = binding.versionNameParent; + mVersionCodeView = binding.versionCode; + mVersionCodeParentView = binding.versionCodeParent; - mIcon = binding.appIcon; - mIcon.setVisibility(View.INVISIBLE); - mIcon.setOnClickListener(v -> selectIcon()); + mIconView = binding.appIcon; + mIconView.setVisibility(View.INVISIBLE); + mIconView.setOnClickListener(v -> selectIcon()); - mAppConfig = binding.appConfig; + mAppConfigView = binding.appConfig; mFlexboxAbis = binding.flexboxAbis; initAbisChildren(); @@ -515,8 +515,8 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa if (dir != null && dir.startsWith(getFilesDir().getPath())) { dir = WorkingDirectoryUtils.getPath(); } - mOutputPath.setText(dir); - mAppName.setText(file.getSimplifiedName()); + mOutputPathView.setText(dir); + mAppNameView.setText(file.getSimplifiedName()); Observable.fromCallable(() -> { String packageNameSuffix = generatePackageNameSuffix(file); @@ -525,34 +525,34 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(packageName -> { - mPackageName.setText(packageName); - mPackageNameParent.setHint(R.string.text_package_name); + mPackageNameView.setText(packageName); + mPackageNameParentView.setHint(R.string.text_package_name); SimpleVersionInfo nextVersionInfo = AppUtils.generateNextVersionInfo(packageName); if (nextVersionInfo != null) { - mVersionName.setText(nextVersionInfo.versionName); - mVersionCode.setText(nextVersionInfo.versionCodeString); + mVersionNameView.setText(nextVersionInfo.versionName); + mVersionCodeView.setText(nextVersionInfo.versionCodeString); } else { - mVersionName.setText(R.string.default_build_apk_version_name); - mVersionCode.setText(R.string.default_build_apk_version_code); + mVersionNameView.setText(R.string.default_build_apk_version_name); + mVersionCodeView.setText(R.string.default_build_apk_version_code); } - mVersionNameParent.setHint(R.string.text_version_name); - mVersionCodeParent.setHint(R.string.text_version_code); + mVersionNameParentView.setHint(R.string.text_version_name); + mVersionCodeParentView.setHint(R.string.text_version_code); Drawable iconDrawable = AppUtils.getInstalledAppIcon(packageName); if (iconDrawable != null) { - mIcon.setImageDrawable(iconDrawable); + mIconView.setImageDrawable(iconDrawable); mIsDefaultIcon = false; } - mIcon.setVisibility(View.VISIBLE); + mIconView.setVisibility(View.VISIBLE); }, throwable -> { - mPackageName.setText(getString(R.string.format_default_package_name, file.getSimplifiedName().toLowerCase(Language.getPrefLanguage().getLocale()))); - mVersionName.setText(R.string.default_build_apk_version_name); - mVersionCode.setText(R.string.default_build_apk_version_code); - mPackageNameParent.setHint(R.string.text_package_name); - mVersionNameParent.setHint(R.string.text_version_name); - mVersionCodeParent.setHint(R.string.text_version_code); - mIcon.setVisibility(View.VISIBLE); + mPackageNameView.setText(getString(R.string.format_default_package_name, file.getSimplifiedName().toLowerCase(Language.getPrefLanguage().getLocale()))); + mVersionNameView.setText(R.string.default_build_apk_version_name); + mVersionCodeView.setText(R.string.default_build_apk_version_code); + mPackageNameParentView.setHint(R.string.text_package_name); + mVersionNameParentView.setHint(R.string.text_version_name); + mVersionCodeParentView.setHint(R.string.text_version_code); + mIconView.setVisibility(View.VISIBLE); }); setSource(file); @@ -579,7 +579,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } void selectSourceFilePath() { - String initialDir = new File(mSourcePath.getText().toString()).getParent(); + String initialDir = new File(mSourcePathView.getText().toString()).getParent(); new FileChooserDialogBuilder(this) .title(R.string.text_source_file_path) .dir(EnvironmentUtils.getExternalStoragePath(), @@ -590,7 +590,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa private void setSource(File file) { if (!file.isDirectory()) { - mSourcePath.setText(file.getPath()); + mSourcePathView.setText(file.getPath()); return; } mProjectConfig = ProjectConfig.fromProjectDir(file.getPath()); @@ -598,20 +598,20 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa return; } mIsProjectLevelBuilding = true; - mOutputPath.setText(new File(mSource, mProjectConfig.getBuildDir()).getPath()); - mAppConfig.setVisibility(View.GONE); - mSourcePathContainer.setVisibility(View.GONE); + mOutputPathView.setText(new File(mSource, mProjectConfig.getBuildDir()).getPath()); + mAppConfigView.setVisibility(View.GONE); + mSourcePathContainerView.setVisibility(View.GONE); } void selectOutputDirPath() { - String initialDir = new File(mOutputPath.getText().toString()).exists() - ? mOutputPath.getText().toString() + String initialDir = new File(mOutputPathView.getText().toString()).exists() + ? mOutputPathView.getText().toString() : WorkingDirectoryUtils.getPath(); new FileChooserDialogBuilder(this) .title(R.string.text_output_apk_path) .dir(initialDir) .chooseDir() - .singleChoice(dir -> mOutputPath.setText(dir.getPath())) + .singleChoice(dir -> mOutputPathView.setText(dir.getPath())) .show(); } @@ -633,14 +633,14 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa private boolean checkInputs() { if (mIsProjectLevelBuilding) { - return checkNotEmpty(mOutputPath); + return checkNotEmpty(mOutputPathView); } - return checkNotEmpty(mSourcePath) - & checkNotEmpty(mOutputPath) - & checkNotEmpty(mAppName) - & checkNotEmpty(mVersionCode) - & checkNotEmpty(mVersionName) - & checkPackageNameValid(mPackageName); + return checkNotEmpty(mSourcePathView) + & checkNotEmpty(mOutputPathView) + & checkNotEmpty(mAppNameView) + & checkNotEmpty(mVersionCodeView) + & checkNotEmpty(mVersionNameView) + & checkPackageNameValid(mPackageNameView); } private boolean checkAbis() { @@ -773,12 +773,12 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa @SuppressWarnings("ResultOfMethodCallIgnored") @SuppressLint("CheckResult") private void doBuildingApk() { - ApkBuilder.AppConfig appConfig = createAppConfig(); + ProjectConfig projectConfig = determineProjectConfig(); File tmpDir = new File(getCacheDir(), "build/"); - File outApk = new File(mOutputPath.getText().toString(), - String.format("%s_v%s.apk", appConfig.getAppName(), appConfig.getVersionName())); + File outApk = new File(mOutputPathView.getText().toString(), + String.format("%s_v%s.apk", projectConfig.getName(), projectConfig.getVersionName())); showProgressDialog(); - Observable.fromCallable(() -> callApkBuilder(tmpDir, outApk, appConfig)) + Observable.fromCallable(() -> callApkBuilder(tmpDir, outApk, projectConfig)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(apkBuilder -> { @@ -790,32 +790,33 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa }, this::onBuildFailed); } - private ApkBuilder.AppConfig createAppConfig() { + private ProjectConfig determineProjectConfig() { ArrayList abis = collectCheckedItems(mFlexboxAbis); ArrayList libs = collectCheckedItems(mFlexboxLibs); ArrayList permissions = collectCheckedItems(mFlexboxPermissions); - ApkBuilder.AppConfig appConfig = mProjectConfig != null - ? ApkBuilder.AppConfig.fromProjectConfig(mSource, mProjectConfig) - : new ApkBuilder.AppConfig() - .setAppName(mAppName.getText().toString()) - .setSourcePath(mSourcePath.getText().toString()) - .setPackageName(mPackageName.getText().toString()) - .setVersionName(mVersionName.getText().toString()) - .setVersionCode(Integer.parseInt(mVersionCode.getText().toString())) - .setIcon(mIsDefaultIcon ? null : () -> BitmapUtils.drawableToBitmap(mIcon.getDrawable())); - - appConfig.setAbis(abis); - appConfig.setLibs(libs); - appConfig.setSignatureSchemes(mSignatureSchemes.getSelectedItem().toString()); - if (mVerifiedKeyStores.getSelectedItemPosition() > 0) { - appConfig.setKeyStore((KeyStore) mVerifiedKeyStores.getSelectedItem()); + ProjectConfig projectConfig; + if (mProjectConfig != null) { + projectConfig = mProjectConfig + .ignoredDir(new File(mSource, mProjectConfig.getBuildDir())) + .setSourcePath(mSource) + .setIconPath(mProjectConfig.getIconPath() == null ? null : new File(mSource, mProjectConfig.getIconPath()).getPath()); } else { - appConfig.setKeyStore(null); + projectConfig = new ProjectConfig() + .setName(mAppNameView.getText().toString()) + .setSourcePath(mSourcePathView.getText().toString()) + .setPackageName(mPackageNameView.getText().toString()) + .setVersionName(mVersionNameView.getText().toString()) + .setVersionCode(Integer.parseInt(mVersionCodeView.getText().toString())) + .setIconGetter(mIsDefaultIcon ? null : () -> BitmapUtils.drawableToBitmap(mIconView.getDrawable())); } - appConfig.setPermissions(permissions); - return appConfig; + return projectConfig + .setAbis(abis) + .setLibs(libs) + .setKeyStore(mVerifiedKeyStores.getSelectedItemPosition() > 0 ? (KeyStore) mVerifiedKeyStores.getSelectedItem() : null) + .setSignatureSchemes(mSignatureSchemes.getSelectedItem().toString()) + .setPermissions(permissions); } @NotNull @@ -843,12 +844,12 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa return libs; } - private ApkBuilder callApkBuilder(File tmpDir, File outApk, ApkBuilder.AppConfig appConfig) throws Exception { + private ApkBuilder callApkBuilder(File tmpDir, File outApk, ProjectConfig projectConfig) throws Exception { InputStream templateApk = getAssets().open(TEMPLATE_APK_NAME); return new ApkBuilder(templateApk, outApk, tmpDir.getPath()) .setProgressCallback(BuildActivity.this) .prepare() - .withConfig(appConfig) + .withConfig(projectConfig) .build() .sign() .cleanWorkspace(); @@ -920,7 +921,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(drawable -> { - mIcon.setImageDrawable(drawable); + mIconView.setImageDrawable(drawable); mIsDefaultIcon = false; }, Throwable::printStackTrace); } diff --git a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.kt b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.kt index 09ac3f4d..13fd547e 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.kt @@ -122,12 +122,12 @@ class ProjectConfigActivity : BaseActivity() { } else { mAppName.setText(config.name) setToolbarAsBack(config.name) - mVersionCode.setText(config.versionCode.toString()) + mVersionCode.setText(config.versionCode.coerceAtLeast(0).toString()) mPackageName.setText(config.packageName) mVersionName.setText(config.versionName) mMainFileName.setText(config.mainScriptFile) mProjectLocationWrapper.visibility = View.GONE - config.icon?.let { icon -> + config.iconPath?.let { icon -> File(mDirectory, icon).takeIf { it.exists() }?.let { iconFile -> Glide.with(this) .load(iconFile) @@ -259,7 +259,7 @@ class ProjectConfigActivity : BaseActivity() { private fun saveIcon(b: Bitmap): Observable { return Observable.just(b) .map { bitmap: Bitmap -> - var iconPath = mProjectConfig!!.icon + var iconPath = mProjectConfig!!.iconPath if (iconPath == null) { iconPath = "res/logo.png" } @@ -272,7 +272,7 @@ class ProjectConfigActivity : BaseActivity() { } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { iconPath: String? -> mProjectConfig!!.icon = iconPath } + .doOnNext { iconPath: String? -> mProjectConfig!!.iconPath = iconPath } } override fun onDestroy() { diff --git a/app/src/main/res/layout/activity_splash_inrt.xml b/app/src/main/res/layout/activity_splash_inrt.xml index 83a31cd4..72f9978d 100644 --- a/app/src/main/res/layout/activity_splash_inrt.xml +++ b/app/src/main/res/layout/activity_splash_inrt.xml @@ -1,27 +1,32 @@ - + + android:id="@+id/icon" + android:visibility="gone" + tools:visibility="visible" + android:layout_width="72dp" + android:layout_height="72dp" + android:layout_gravity="center" + android:src="@mipmap/ic_launcher" /> + android:id="@+id/slug" + android:visibility="gone" + tools:visibility="visible" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="20dp" + android:text="@string/text_powered_by_autojs" + android:textColor="@color/day_night_full" + android:textSize="16sp" /> \ No newline at end of file diff --git a/version.properties b/version.properties index 323459ed..23ae2cb4 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Sat Jan 18 23:47:18 CST 2025 -BUILD_TIME=1737215238545 +#Mon Jan 20 14:32:52 CST 2025 +BUILD_TIME=1737354772708 COMPILE_SDK_VERSION=34 JAVA_VERSION=23 JAVA_VERSION_MIN_RADICAL=0 @@ -17,6 +17,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=34 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=2977 +VERSION_BUILD=2979 VERSION_NAME=6.6.2 Alpha2 VSCODE_EXT_REQUIRED_VERSION=1.0.8