6.7.0 - Alpha23 - 优化打包过程对话框显示方式; 打包过程支持操作中止
This commit is contained in:
@@ -36,14 +36,18 @@ import pxb.android.StringItem
|
||||
import pxb.android.axml.AxmlWriter
|
||||
import zhao.arsceditor.ResDecoder.ARSCDecoder
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.concurrent.CancellationException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
@@ -59,6 +63,9 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
private var mManifestEditor: ManifestEditor? = null
|
||||
private var mInitVector: String? = null
|
||||
private var mKey: String? = null
|
||||
private var mCancelSignal: AtomicBoolean? = null
|
||||
private var mPendingProjectConfigFile: File? = null
|
||||
private var mPendingProjectConfigJson: String? = null
|
||||
|
||||
private lateinit var mProjectConfig: ProjectConfig
|
||||
|
||||
@@ -85,49 +92,157 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
|
||||
fun setProgressCallback(callback: ProgressCallback?) = also { mProgressCallback = callback }
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun prepare() = also {
|
||||
mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onPrepare(this) } }
|
||||
File(buildPath).mkdirs()
|
||||
mApkPackager.unzip()
|
||||
fun setCancelSignal(cancelSignal: AtomicBoolean?) = also {
|
||||
mCancelSignal = cancelSignal
|
||||
mApkPackager.setCancelSignal(cancelSignal)
|
||||
}
|
||||
|
||||
// Throw early when cancellation is requested to avoid partial outputs.
|
||||
// zh-CN: 当收到取消请求时尽早抛出, 以避免产生部分输出.
|
||||
private fun ensureNotCancelled() {
|
||||
if (mCancelSignal?.get() == true) {
|
||||
throw CancellationException("Build aborted")
|
||||
}
|
||||
if (Thread.currentThread().isInterrupted) {
|
||||
throw CancellationException("Build aborted")
|
||||
}
|
||||
}
|
||||
|
||||
// Copy streams with cancellation checks to keep abort responsive during large IO.
|
||||
// zh-CN: 在大 IO 过程中加入取消检查, 保持中止响应.
|
||||
private fun copyStreamWithCancel(input: InputStream, output: OutputStream, bufferSize: Int = 16 * 1024) {
|
||||
val buffer = ByteArray(bufferSize)
|
||||
var len: Int
|
||||
while (input.read(buffer).also { len = it } > 0) {
|
||||
ensureNotCancelled()
|
||||
output.write(buffer, 0, len)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyStepChanged(step: ProgressStep) {
|
||||
mProgressCallback?.let { callback ->
|
||||
GlobalAppContext.post {
|
||||
when (step) {
|
||||
ProgressStep.PREPARE -> callback.onPrepare(this)
|
||||
ProgressStep.BUILD -> callback.onBuild(this)
|
||||
ProgressStep.SIGN -> callback.onSign(this)
|
||||
ProgressStep.CLEAN -> callback.onClean(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyStepProgress(step: ProgressStep, title: String, detail: String?) {
|
||||
mProgressCallback?.let { callback ->
|
||||
GlobalAppContext.post {
|
||||
callback.onStepProgress(
|
||||
builder = this,
|
||||
title = title,
|
||||
detail = detail?.takeIf { it.isNotBlank() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun setScriptFile(path: String?) = also {
|
||||
fun prepare(context: Context) = also {
|
||||
ensureNotCancelled()
|
||||
notifyStepChanged(ProgressStep.PREPARE)
|
||||
notifyStepProgress(
|
||||
ProgressStep.PREPARE,
|
||||
context.getString(R.string.text_preparing_workspace),
|
||||
buildPath,
|
||||
)
|
||||
File(buildPath).mkdirs()
|
||||
notifyStepProgress(
|
||||
ProgressStep.PREPARE,
|
||||
context.getString(R.string.text_extracting_template_apk),
|
||||
buildPath,
|
||||
)
|
||||
mApkPackager.unzip()
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.PREPARE,
|
||||
context.getString(R.string.text_prepare_completed),
|
||||
buildPath,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun setScriptFile(context: Context, path: String?) = also {
|
||||
ensureNotCancelled()
|
||||
path?.let {
|
||||
when {
|
||||
PFiles.isDir(it) -> copyDir(it, "assets/project/")
|
||||
else -> replaceFile(it, "assets/project/main.js")
|
||||
PFiles.isDir(it) -> {
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_project_directory),
|
||||
it,
|
||||
)
|
||||
copyDir(context, it, "assets/project/")
|
||||
}
|
||||
else -> {
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_script_file),
|
||||
it,
|
||||
)
|
||||
replaceFile(context, it, "assets/project/main.js")
|
||||
}
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_source_processing_completed),
|
||||
it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@Suppress("SameParameterValue")
|
||||
private fun copyDir(srcPath: String, relativeDestPath: String) {
|
||||
copyDir(File(srcPath), relativeDestPath)
|
||||
private fun copyDir(context: Context, srcPath: String, relativeDestPath: String) {
|
||||
copyDir(context, File(srcPath), relativeDestPath)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun copyDir(srcFile: File, relativeDestPath: String) {
|
||||
fun copyDir(context: Context, srcFile: File, relativeDestPath: String) {
|
||||
ensureNotCancelled()
|
||||
val destDirFile = File(buildPath, relativeDestPath).apply { mkdir() }
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_directory),
|
||||
"${srcFile.path} -> ${destDirFile.path}",
|
||||
)
|
||||
srcFile.listFiles()?.forEach { srcChildFile ->
|
||||
ensureNotCancelled()
|
||||
if (srcChildFile.isFile) {
|
||||
if (srcChildFile.name.endsWith(JAVASCRIPT.extensionWithDot)) {
|
||||
encryptToDir(srcChildFile, destDirFile)
|
||||
encryptToDir(context, srcChildFile, destDirFile)
|
||||
} else {
|
||||
srcChildFile.copyTo(File(destDirFile, srcChildFile.name), true)
|
||||
val destFile = File(destDirFile, srcChildFile.name)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_file),
|
||||
"${srcChildFile.path} -> ${destFile.path}",
|
||||
)
|
||||
srcChildFile.copyTo(destFile, true)
|
||||
}
|
||||
} else {
|
||||
if (!mProjectConfig.excludedDirs.contains(srcChildFile)) {
|
||||
copyDir(srcChildFile, PFiles.join(relativeDestPath, srcChildFile.name + File.separator))
|
||||
copyDir(context, srcChildFile, PFiles.join(relativeDestPath, srcChildFile.name + File.separator))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun encrypt(srcFile: File, destFile: File) {
|
||||
private fun encrypt(context: Context, srcFile: File, destFile: File) {
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_encrypting_script),
|
||||
"${srcFile.path} -> ${destFile.path}",
|
||||
)
|
||||
destFile.outputStream().use { os ->
|
||||
writeHeader(os, JavaScriptFileSource(srcFile).executionMode.toShort())
|
||||
AdvancedEncryptionStandard(mKey!!.toByteArray(), mInitVector!!)
|
||||
@@ -136,34 +251,93 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
}
|
||||
|
||||
private fun encryptToDir(srcFile: File, destDirFile: File) {
|
||||
private fun encryptToDir(context: Context, srcFile: File, destDirFile: File) {
|
||||
val destFile = File(destDirFile, srcFile.name)
|
||||
encrypt(srcFile, destFile)
|
||||
encrypt(context, srcFile, destFile)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun replaceFile(srcPath: String, relativeDestPath: String) = replaceFile(File(srcPath), relativeDestPath)
|
||||
fun replaceFile(context: Context, srcPath: String, relativeDestPath: String) = replaceFile(context, File(srcPath), relativeDestPath)
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun replaceFile(srcFile: File, relativeDestPath: String) = also {
|
||||
fun replaceFile(context: Context, srcFile: File, relativeDestPath: String) = also {
|
||||
ensureNotCancelled()
|
||||
val destFile = File(buildPath, relativeDestPath)
|
||||
if (destFile.name.endsWith(JAVASCRIPT.extensionWithDot)) {
|
||||
encrypt(srcFile, destFile)
|
||||
encrypt(context, srcFile, destFile)
|
||||
} else {
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_replacing_file),
|
||||
"${srcFile.path} -> ${destFile.path}",
|
||||
)
|
||||
srcFile.copyTo(destFile, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun withConfig(config: ProjectConfig) = also {
|
||||
fun withConfig(context: Context, config: ProjectConfig) = also {
|
||||
notifyStepChanged(ProgressStep.BUILD)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_preparing_build_config),
|
||||
)
|
||||
config.also { mProjectConfig = it }.run {
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_reading_splash_resources),
|
||||
mResourcesArscFile.path,
|
||||
)
|
||||
retrieveSplashThemeResources(launchConfig)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_configuring_manifest),
|
||||
mManifestFile.path,
|
||||
)
|
||||
prepareManifestConfiguration(this)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_configuring_package_name),
|
||||
packageName,
|
||||
)
|
||||
setArscPackageName(packageName)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_updating_project_config),
|
||||
)
|
||||
updateProjectConfig(this)
|
||||
copyAssetsRecursively("", File(buildPath, "assets"))
|
||||
copyLibrariesByConfig(this)
|
||||
setScriptFile(sourcePath)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_assets_to),
|
||||
File(buildPath, "assets").path,
|
||||
)
|
||||
copyAssetsRecursively(context, "", File(buildPath, "assets"))
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_copying_native_libraries),
|
||||
)
|
||||
copyLibrariesByConfig(context, this)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing_source),
|
||||
sourcePath,
|
||||
)
|
||||
setScriptFile(context, sourcePath)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_applying_binary_resources),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +377,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
fun editManifest(): ManifestEditor = ManifestEditorWithAuthorities(FileInputStream(mManifestFile)).also { mManifestEditor = it }
|
||||
|
||||
private fun updateProjectConfig(config: ProjectConfig) {
|
||||
ensureNotCancelled()
|
||||
|
||||
// 这里为什么要有这样的一个方法? (
|
||||
// 会不会是因为有些配置需要写入到文件中, 这些配置包括自增的版本号, 用户的选择或键入值等等
|
||||
@@ -222,7 +397,8 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
ProjectConfig.fromProjectDir(config.sourcePath)?.let { sourceProjectConfig ->
|
||||
sourceProjectConfig
|
||||
.setBuildInfo(BuildInfo.generate(sourceProjectConfig.buildInfo.buildNumber + 1))
|
||||
File(ProjectConfig.configFileOfDir(config.sourcePath)).writeText(sourceProjectConfig.toJson(true))
|
||||
mPendingProjectConfigFile = File(ProjectConfig.configFileOfDir(config.sourcePath))
|
||||
mPendingProjectConfigJson = sourceProjectConfig.toJson(true)
|
||||
return@run sourceProjectConfig
|
||||
}
|
||||
}
|
||||
@@ -254,11 +430,46 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
}
|
||||
|
||||
// Commit project config changes only after a successful build.
|
||||
// zh-CN: 仅在构建成功后提交项目配置变更.
|
||||
fun commitProjectConfigIfNeeded(context: Context) = also {
|
||||
val pendingFile = mPendingProjectConfigFile
|
||||
val pendingJson = mPendingProjectConfigJson
|
||||
if (pendingFile == null || pendingJson == null) {
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_sign_stage_completed),
|
||||
)
|
||||
return@also
|
||||
}
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_writing_project_config),
|
||||
pendingFile.path,
|
||||
)
|
||||
pendingFile.writeText(pendingJson)
|
||||
mPendingProjectConfigFile = null
|
||||
mPendingProjectConfigJson = null
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_sign_stage_completed),
|
||||
)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun build() = also {
|
||||
mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onBuild(this) } }
|
||||
fun build(context: Context) = also {
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_building_resources),
|
||||
)
|
||||
mProjectConfig.iconBitmapGetter?.let { callable ->
|
||||
runCatching {
|
||||
ensureNotCancelled()
|
||||
val tableBlock = TableBlock.load(mResourcesArscFile)
|
||||
val packageName = "${GlobalAppContext.get().packageName}.inrt"
|
||||
val packageBlock = tableBlock.getOrCreatePackage(0x7f, packageName).also {
|
||||
@@ -273,17 +484,42 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
it.createNewFile()
|
||||
}
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_writing_app_icon),
|
||||
file.path,
|
||||
)
|
||||
callable.call()?.compress(Bitmap.CompressFormat.PNG, 100, FileOutputStream(file))
|
||||
}.onFailure { throw RuntimeException(it) }
|
||||
}
|
||||
mManifestEditor?.let {
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_writing_manifest),
|
||||
mManifestFile.path,
|
||||
)
|
||||
it.commit()
|
||||
it.writeTo(FileOutputStream(mManifestFile))
|
||||
}
|
||||
mArscPackageName?.let { buildArsc() }
|
||||
mArscPackageName?.let {
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_writing_resources_arsc),
|
||||
mResourcesArscFile.path,
|
||||
)
|
||||
buildArsc()
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_build_completed),
|
||||
)
|
||||
}
|
||||
|
||||
private fun copyAssetsRecursively(assetPath: String, targetFile: File) {
|
||||
private fun copyAssetsRecursively(context: Context, assetPath: String, targetFile: File) {
|
||||
ensureNotCancelled()
|
||||
if (targetFile.isFile && targetFile.exists()) return
|
||||
val list = mAssetManager.list(assetPath) ?: return
|
||||
if (list.isEmpty()) /* asset is a file */ {
|
||||
@@ -292,9 +528,14 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
return
|
||||
}
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_asset),
|
||||
"assets/$assetPath -> ${targetFile.path}",
|
||||
)
|
||||
mAssetManager.open(assetPath).use { input ->
|
||||
FileOutputStream(targetFile.absolutePath).use { output ->
|
||||
input.copyTo(output)
|
||||
copyStreamWithCancel(input, output)
|
||||
output.flush()
|
||||
}
|
||||
}
|
||||
@@ -302,36 +543,80 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
if (mAssetsDirExcludes.any { assetPath.matches(Regex("$it(/[^/]+)*")) }) {
|
||||
return
|
||||
}
|
||||
val displayPath = if (assetPath.isEmpty()) "/" else "/$assetPath"
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_preparing_assets_dir),
|
||||
displayPath,
|
||||
)
|
||||
targetFile.delete()
|
||||
targetFile.mkdir()
|
||||
list.forEach {
|
||||
ensureNotCancelled()
|
||||
val sourcePath = if (assetPath.isEmpty()) it else "$assetPath/$it"
|
||||
copyAssetsRecursively(sourcePath, File(targetFile, it))
|
||||
copyAssetsRecursively(context, sourcePath, File(targetFile, it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun sign() = also {
|
||||
mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onSign(this) } }
|
||||
val fos = FileOutputStream(outApkFile)
|
||||
TinySign.sign(File(buildPath), fos)
|
||||
fos.close()
|
||||
fun sign(context: Context) = also {
|
||||
ensureNotCancelled()
|
||||
notifyStepChanged(ProgressStep.SIGN)
|
||||
val workspaceDir = File(buildPath)
|
||||
outApkFile.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
val unsignedApkFile = outApkFile
|
||||
val tmpOutputApk = File(outApkFile.parentFile ?: workspaceDir, "${outApkFile.name}.signed.tmp")
|
||||
if (tmpOutputApk.exists()) {
|
||||
tmpOutputApk.delete()
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_creating_unsigned_apk),
|
||||
unsignedApkFile.path,
|
||||
)
|
||||
try {
|
||||
BufferedOutputStream(FileOutputStream(unsignedApkFile, false), 256 * 1024).use { fos ->
|
||||
TinySign.sign(workspaceDir, fos)
|
||||
fos.flush()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (tmpOutputApk.exists() && !tmpOutputApk.delete()) {
|
||||
Log.w(TAG, "Failed to delete temporary signed apk after unsigned apk creation failure: ${tmpOutputApk.path}")
|
||||
}
|
||||
if (e.hasNoSpaceLeft()) {
|
||||
throw IOException("No space left on device while creating unsigned APK: ${unsignedApkFile.path}", e)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_unsigned_apk_created),
|
||||
unsignedApkFile.path,
|
||||
)
|
||||
|
||||
val defaultKeyStoreFile = File(buildPath, "default_key_store.bks")
|
||||
val tmpOutputApk = File(buildPath, "temp.apk")
|
||||
if (mProjectConfig.keyStore == null) {
|
||||
|
||||
// Replace FileUtils.copyInputStreamToFile(...).
|
||||
// zh-CN: 替换 FileUtils.copyInputStreamToFile(...).
|
||||
defaultKeyStoreFile.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
GlobalAppContext.get().assets.open("default_key_store.bks").use { input ->
|
||||
FileOutputStream(defaultKeyStoreFile, false).use { output ->
|
||||
input.copyTo(output, bufferSize = 16 * 1024)
|
||||
output.fd.sync()
|
||||
// Replace FileUtils.copyInputStreamToFile(...).
|
||||
// zh-CN: 替换 FileUtils.copyInputStreamToFile(...).
|
||||
ensureNotCancelled()
|
||||
defaultKeyStoreFile.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_preparing_keystore),
|
||||
defaultKeyStoreFile.path,
|
||||
)
|
||||
GlobalAppContext.get().assets.open("default_key_store.bks").use { input ->
|
||||
FileOutputStream(defaultKeyStoreFile, false).use { output ->
|
||||
copyStreamWithCancel(input, output)
|
||||
output.fd.sync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val signer = ApkSigner(outApkFile, tmpOutputApk).apply {
|
||||
ensureNotCancelled()
|
||||
val signer = ApkSigner(unsignedApkFile, tmpOutputApk).apply {
|
||||
useDefaultSignatureVersion = false
|
||||
v1SigningEnabled = "V1" in mProjectConfig.signatureScheme
|
||||
v2SigningEnabled = "V2" in mProjectConfig.signatureScheme
|
||||
@@ -350,24 +635,84 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
alias = it.alias
|
||||
aliasPassword = AESUtils.decrypt(it.aliasPassword)
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_using_keystore),
|
||||
keyStoreFile.path,
|
||||
)
|
||||
|
||||
// Re-sign using ApkSigner.
|
||||
// zh-CN: 使用 ApkSigner 重新签名.
|
||||
if (!signer.signRelease(keyStoreFile, password, alias, aliasPassword)) {
|
||||
throw java.lang.RuntimeException("Failed to re-sign using ApkSigner")
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_re_signing_apk),
|
||||
)
|
||||
try {
|
||||
if (!signer.signRelease(keyStoreFile, password, alias, aliasPassword)) {
|
||||
throw RuntimeException("Failed to re-sign using ApkSigner")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (tmpOutputApk.exists() && !tmpOutputApk.delete()) {
|
||||
Log.w(TAG, "Failed to delete temporary signed apk after re-sign failure: ${tmpOutputApk.path}")
|
||||
}
|
||||
if (e.hasNoSpaceLeft()) {
|
||||
throw IOException("No space left on device while re-signing APK: ${tmpOutputApk.path}", e)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
try {
|
||||
outApkFile.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
tmpOutputApk.copyTo(outApkFile, overwrite = true)
|
||||
} catch (e: java.lang.Exception) {
|
||||
throw java.lang.RuntimeException(e)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_writing_signed_apk),
|
||||
outApkFile.path,
|
||||
)
|
||||
if (outApkFile.exists() && !outApkFile.delete()) {
|
||||
throw IOException("Failed to delete unsigned apk before replace: ${outApkFile.path}")
|
||||
}
|
||||
if (!tmpOutputApk.renameTo(outApkFile)) {
|
||||
copyFileWithLargeBuffer(tmpOutputApk, outApkFile)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e.hasNoSpaceLeft()) {
|
||||
throw IOException("No space left on device while writing signed APK: ${outApkFile.path}", e)
|
||||
}
|
||||
throw RuntimeException(e)
|
||||
} finally {
|
||||
if (tmpOutputApk.exists() && !tmpOutputApk.delete()) {
|
||||
Log.w(TAG, "Failed to delete temporary signed apk: ${tmpOutputApk.path}")
|
||||
}
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.SIGN,
|
||||
context.getString(R.string.text_sign_completed),
|
||||
outApkFile.path,
|
||||
)
|
||||
}
|
||||
|
||||
fun cleanWorkspace() = also {
|
||||
mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onClean(this) } }
|
||||
delete(File(buildPath))
|
||||
fun cleanWorkspace(context: Context) = also {
|
||||
notifyStepChanged(ProgressStep.CLEAN)
|
||||
val workspace = File(buildPath)
|
||||
val totalTargets = countDeleteTargets(workspace).coerceAtLeast(1)
|
||||
val deletedTargets = intArrayOf(0)
|
||||
notifyStepProgress(
|
||||
ProgressStep.CLEAN,
|
||||
context.getString(R.string.text_cleaning_workspace),
|
||||
workspace.path,
|
||||
)
|
||||
deleteWithProgress(context, workspace, totalTargets, deletedTargets)
|
||||
notifyStepProgress(
|
||||
ProgressStep.CLEAN,
|
||||
context.getString(R.string.text_clean_completed),
|
||||
workspace.path,
|
||||
)
|
||||
}
|
||||
|
||||
fun finish() = also {
|
||||
mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onFinished(this) } }
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -377,23 +722,86 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
private fun buildArsc() {
|
||||
val oldArsc = File(buildPath, "resources.arsc")
|
||||
val newArsc = File(buildPath, "resources.arsc.new")
|
||||
val decoder = ARSCDecoder(BufferedInputStream(FileInputStream(oldArsc)), null, false)
|
||||
decoder.CloneArsc(FileOutputStream(newArsc), mArscPackageName, true)
|
||||
BufferedInputStream(FileInputStream(oldArsc), 256 * 1024).use { input ->
|
||||
BufferedOutputStream(FileOutputStream(newArsc, false), 256 * 1024).use { output ->
|
||||
val decoder = ARSCDecoder(input, null, false)
|
||||
decoder.CloneArsc(output, mArscPackageName, true)
|
||||
output.flush()
|
||||
}
|
||||
}
|
||||
oldArsc.delete()
|
||||
newArsc.renameTo(oldArsc)
|
||||
if (!newArsc.renameTo(oldArsc)) {
|
||||
copyFileWithLargeBuffer(newArsc, oldArsc)
|
||||
newArsc.delete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun delete(file: File) {
|
||||
file.apply { if (isDirectory) listFiles()?.forEach { delete(it) } }.also { it.delete() }
|
||||
private fun copyFileWithLargeBuffer(source: File, target: File, bufferSize: Int = 256 * 1024) {
|
||||
FileInputStream(source).use { input ->
|
||||
FileOutputStream(target, false).use { output ->
|
||||
val buffer = ByteArray(bufferSize)
|
||||
var len: Int
|
||||
while (input.read(buffer).also { len = it } > 0) {
|
||||
ensureNotCancelled()
|
||||
output.write(buffer, 0, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Throwable.hasNoSpaceLeft(): Boolean {
|
||||
var current: Throwable? = this
|
||||
while (current != null) {
|
||||
val message = current.message.orEmpty()
|
||||
if (message.contains("ENOSPC", ignoreCase = true) || message.contains("No space left on device", ignoreCase = true)) {
|
||||
return true
|
||||
}
|
||||
current = current.cause
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun countDeleteTargets(file: File): Int {
|
||||
if (!file.exists()) {
|
||||
return 0
|
||||
}
|
||||
return if (file.isDirectory) {
|
||||
1 + (file.listFiles()?.sumOf(::countDeleteTargets) ?: 0)
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteWithProgress(context: Context, file: File, totalTargets: Int, deletedTargets: IntArray) {
|
||||
ensureNotCancelled()
|
||||
if (file.isDirectory) {
|
||||
file.listFiles()?.forEach { child ->
|
||||
deleteWithProgress(context, child, totalTargets, deletedTargets)
|
||||
}
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.CLEAN,
|
||||
context.getString(R.string.text_deleting),
|
||||
file.path,
|
||||
)
|
||||
file.delete()
|
||||
deletedTargets[0] += 1
|
||||
}
|
||||
|
||||
enum class ProgressStep {
|
||||
PREPARE,
|
||||
BUILD,
|
||||
SIGN,
|
||||
CLEAN,
|
||||
}
|
||||
|
||||
interface ProgressCallback {
|
||||
|
||||
fun onPrepare(builder: ApkBuilder)
|
||||
fun onBuild(builder: ApkBuilder)
|
||||
fun onSign(builder: ApkBuilder)
|
||||
fun onClean(builder: ApkBuilder)
|
||||
|
||||
fun onStepProgress(builder: ApkBuilder, title: String, detail: String?)
|
||||
fun onFinished(builder: ApkBuilder)
|
||||
}
|
||||
|
||||
private inner class ManifestEditorWithAuthorities(manifestInputStream: InputStream?) : ManifestEditor(manifestInputStream) {
|
||||
@@ -422,7 +830,8 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLibrariesByConfig(config: ProjectConfig) {
|
||||
private fun copyLibrariesByConfig(context: Context, config: ProjectConfig) {
|
||||
ensureNotCancelled()
|
||||
|
||||
// @Hint by SuperMonster003 on Dec 11, 2023.
|
||||
// ! The list contains only abi names not matching the canonical name itself.
|
||||
@@ -434,47 +843,78 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
|
||||
// Try extracting native libraries from installed plugin APKs if needed.
|
||||
// zh-CN: 如有需要, 尝试从已安装插件 APK 中解压 native 库文件.
|
||||
ensureAndExtractPluginLibrariesIfNeeded(config, potentialAbiAliasList)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_processing),
|
||||
context.getString(R.string.text_resolving_plugin_native_libraries),
|
||||
)
|
||||
ensureAndExtractPluginLibrariesIfNeeded(context, config, potentialAbiAliasList)
|
||||
|
||||
config.abis.forEach { abiCanonicalName ->
|
||||
copyLibrariesByAbi(abiCanonicalName, abiCanonicalName)
|
||||
ensureNotCancelled()
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_libraries_for_abi),
|
||||
abiCanonicalName,
|
||||
)
|
||||
copyLibrariesByAbi(context, abiCanonicalName, abiCanonicalName)
|
||||
potentialAbiAliasList[abiCanonicalName]?.let { abiAliasName ->
|
||||
copyLibrariesByAbi(abiAliasName, abiCanonicalName)
|
||||
copyLibrariesByAbi(context, abiAliasName, abiCanonicalName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureAndExtractPluginLibrariesIfNeeded(
|
||||
context: Context,
|
||||
config: ProjectConfig,
|
||||
potentialAbiAliasList: Map<String, String>,
|
||||
) {
|
||||
ensureNotCancelled()
|
||||
Lib.entries.mapNotNull {
|
||||
if (it.isPlugin && config.libs.contains(it.label)) it.toPluginPair() else null
|
||||
}.forEach { (lib, plugin) ->
|
||||
ensureNotCancelled()
|
||||
// Select plugin service by variant.
|
||||
// zh-CN: 通过 variant 选择插件服务.
|
||||
val (serviceInfo, selectedVariant) = selectPluginServiceOrThrow(
|
||||
lib = lib,
|
||||
action = plugin.action,
|
||||
)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_selected_plugin),
|
||||
"${lib.label} (${selectedVariant.variant}) from ${serviceInfo.packageName}",
|
||||
)
|
||||
|
||||
Log.i(TAG, "Selected ${lib.label} plugin: variant=${selectedVariant.variant}, pkg=${serviceInfo.packageName}")
|
||||
|
||||
// Extract libraries from installed plugin APK (variant-aware).
|
||||
// zh-CN: 从已安装插件 APK 中解压 so 文件, 并按变体裁剪.
|
||||
extractLibrariesFromPluginApkOrThrow(
|
||||
context = context,
|
||||
config = config,
|
||||
requiredLibNames = selectedVariant.libsToInclude,
|
||||
serviceInfo = serviceInfo,
|
||||
potentialAbiAliasList = potentialAbiAliasList,
|
||||
)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_extracted_plugin_libraries),
|
||||
lib.label,
|
||||
)
|
||||
|
||||
// Extract assets (models/labels) from installed plugin APK (variant-aware).
|
||||
// zh-CN: 从已安装插件 APK 中解压 assets 资源 (models/labels), 并按变体裁剪.
|
||||
extractAssetsFromPluginApkOrThrow(
|
||||
context = context,
|
||||
serviceInfo = serviceInfo,
|
||||
pluginLibVariant = selectedVariant,
|
||||
)
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_extracted_plugin_assets),
|
||||
lib.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +922,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
lib: Lib,
|
||||
action: String,
|
||||
): Pair<ServiceInfo, PluginLibVariant> {
|
||||
ensureNotCancelled()
|
||||
val pm = globalContext.packageManager
|
||||
val moduleLabel = lib.label
|
||||
val pluginPair = lib.toPluginPair()
|
||||
@@ -526,6 +967,7 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
|
||||
private fun queryPluginInfoBlocking(context: Context, serviceInfo: ServiceInfo, pluginPair: Pair<Lib, PluginLib>): PluginLibVariant {
|
||||
ensureNotCancelled()
|
||||
// Bind service and call getInfo() synchronously (packaging-time only).
|
||||
// zh-CN: 同步绑定服务并调用 getInfo() (仅打包阶段使用).
|
||||
val latch = CountDownLatch(1)
|
||||
@@ -586,9 +1028,11 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
|
||||
private fun extractAssetsFromPluginApkOrThrow(
|
||||
context: Context,
|
||||
serviceInfo: ServiceInfo,
|
||||
pluginLibVariant: PluginLibVariant,
|
||||
) {
|
||||
ensureNotCancelled()
|
||||
val pm = globalContext.packageManager
|
||||
|
||||
val appInfo = getApplicationInfoCompat(pm, serviceInfo.packageName)
|
||||
@@ -603,7 +1047,9 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
// zh-CN: 解压必需前缀.
|
||||
val missingRequired = mutableListOf<String>()
|
||||
requiredPrefixes.forEach { prefix ->
|
||||
ensureNotCancelled()
|
||||
val ok = extractAssetsByPrefixFromApks(
|
||||
context = context,
|
||||
apkPaths = apkPaths,
|
||||
assetPrefix = prefix,
|
||||
)
|
||||
@@ -620,7 +1066,9 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
// Extract optional prefixes (best-effort).
|
||||
// zh-CN: 解压可选前缀 (尽力而为).
|
||||
optionalPrefixes.forEach { prefix ->
|
||||
ensureNotCancelled()
|
||||
extractAssetsByPrefixFromApks(
|
||||
context = context,
|
||||
apkPaths = apkPaths,
|
||||
assetPrefix = prefix,
|
||||
)
|
||||
@@ -628,15 +1076,19 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
|
||||
private fun extractAssetsByPrefixFromApks(
|
||||
context: Context,
|
||||
apkPaths: List<String>,
|
||||
assetPrefix: String,
|
||||
): Boolean {
|
||||
ensureNotCancelled()
|
||||
var extractedAny = false
|
||||
apkPaths.forEach { apkPath ->
|
||||
ensureNotCancelled()
|
||||
runCatching {
|
||||
ZipFile(apkPath).use { zip ->
|
||||
val entries = zip.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
ensureNotCancelled()
|
||||
val entry: ZipEntry = entries.nextElement()
|
||||
val name = entry.name
|
||||
if (!name.startsWith(assetPrefix)) continue
|
||||
@@ -646,10 +1098,15 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
val outFile = File(buildPath, "assets/$relative").apply {
|
||||
parentFile?.let { parent -> if (!parent.exists()) parent.mkdirs() }
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_extracting_plugin_asset),
|
||||
"$apkPath!/$name -> ${outFile.path}",
|
||||
)
|
||||
|
||||
zip.getInputStream(entry).use { input ->
|
||||
FileOutputStream(outFile, false).use { output ->
|
||||
input.copyTo(output, bufferSize = 16 * 1024)
|
||||
copyStreamWithCancel(input, output)
|
||||
output.fd.sync()
|
||||
}
|
||||
}
|
||||
@@ -667,11 +1124,13 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
|
||||
private fun extractLibrariesFromPluginApkOrThrow(
|
||||
context: Context,
|
||||
config: ProjectConfig,
|
||||
requiredLibNames: List<String>,
|
||||
serviceInfo: ServiceInfo,
|
||||
potentialAbiAliasList: Map<String, String>,
|
||||
) {
|
||||
ensureNotCancelled()
|
||||
val pm = globalContext.packageManager
|
||||
|
||||
val appInfo = getApplicationInfoCompat(pm, serviceInfo.packageName)
|
||||
@@ -683,13 +1142,16 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
val missingPairs = mutableListOf<Pair<String, String>>() // (abi, soName)
|
||||
|
||||
config.abis.forEach { abiCanonicalName ->
|
||||
ensureNotCancelled()
|
||||
val abiCandidates = buildList {
|
||||
add(abiCanonicalName)
|
||||
potentialAbiAliasList[abiCanonicalName]?.let { add(it) }
|
||||
}.distinct()
|
||||
|
||||
requiredLibNames.forEach { soName ->
|
||||
ensureNotCancelled()
|
||||
val ok = extractFirstMatchedSoFromApks(
|
||||
context = context,
|
||||
apkPaths = apkPaths,
|
||||
abiCandidates = abiCandidates,
|
||||
soName = soName,
|
||||
@@ -718,23 +1180,32 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
|
||||
private fun extractFirstMatchedSoFromApks(
|
||||
context: Context,
|
||||
apkPaths: List<String>,
|
||||
abiCandidates: List<String>,
|
||||
soName: String,
|
||||
abiDestName: String,
|
||||
): Boolean {
|
||||
ensureNotCancelled()
|
||||
apkPaths.forEach { apkPath ->
|
||||
ensureNotCancelled()
|
||||
runCatching {
|
||||
ZipFile(apkPath).use { zip ->
|
||||
abiCandidates.forEach { abiInApk ->
|
||||
ensureNotCancelled()
|
||||
val entryName = "lib/$abiInApk/$soName"
|
||||
val entry = zip.getEntry(entryName) ?: return@forEach
|
||||
val outFile = File(buildPath, "lib/$abiDestName/$soName").apply {
|
||||
parentFile?.let { parent -> if (!parent.exists()) parent.mkdirs() }
|
||||
}
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_extracting_plugin_so),
|
||||
"$apkPath!/$entryName -> ${outFile.path}",
|
||||
)
|
||||
zip.getInputStream(entry).use { input ->
|
||||
FileOutputStream(outFile, false).use { output ->
|
||||
input.copyTo(output, bufferSize = 16 * 1024)
|
||||
copyStreamWithCancel(input, output)
|
||||
output.fd.sync()
|
||||
}
|
||||
}
|
||||
@@ -760,18 +1231,26 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLibrariesByAbi(abiSrcName: String, abiDestName: String) {
|
||||
private fun copyLibrariesByAbi(context: Context, abiSrcName: String, abiDestName: String) {
|
||||
ensureNotCancelled()
|
||||
|
||||
// @Reference to LZX284 (https://github.com/LZX284) by SuperMonster003 on Dec 11, 2023.
|
||||
// ! http://pr.autojs6.com/187/files#diff-d932ac49867d4610f8eeb21b59306e8e923d016cbca192b254caebd829198856R61
|
||||
val srcLibDir = File(appApkFile.parent, LIBRARY_DIR).path
|
||||
|
||||
mLibsIncludes.distinct().forEach { libName ->
|
||||
ensureNotCancelled()
|
||||
runCatching {
|
||||
File(srcLibDir, "$abiSrcName/$libName").takeIf { it.exists() }?.copyTo(
|
||||
File(buildPath, "lib/$abiDestName/$libName"),
|
||||
overwrite = true
|
||||
)
|
||||
val srcFile = File(srcLibDir, "$abiSrcName/$libName")
|
||||
val destFile = File(buildPath, "lib/$abiDestName/$libName")
|
||||
srcFile.takeIf { it.exists() }?.let {
|
||||
notifyStepProgress(
|
||||
ProgressStep.BUILD,
|
||||
context.getString(R.string.text_copying_library),
|
||||
"${srcFile.path} -> ${destFile.path}",
|
||||
)
|
||||
it.copyTo(destFile, overwrite = true)
|
||||
}
|
||||
}.onFailure { it.printStackTrace() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@ import android.text.TextUtils;
|
||||
|
||||
import org.autojs.autojs.apkbuilder.util.StreamUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
@@ -20,8 +24,9 @@ import pxb.android.tinysign.TinySign;
|
||||
*/
|
||||
public class ApkPackager {
|
||||
|
||||
private InputStream mApkInputStream;
|
||||
private String mWorkspacePath;
|
||||
private final InputStream mApkInputStream;
|
||||
private final String mWorkspacePath;
|
||||
private AtomicBoolean mCancelSignal;
|
||||
|
||||
public ApkPackager(InputStream apkInputStream, String workspacePath) {
|
||||
mApkInputStream = apkInputStream;
|
||||
@@ -33,20 +38,47 @@ public class ApkPackager {
|
||||
mWorkspacePath = workspacePath;
|
||||
}
|
||||
|
||||
public ApkPackager setCancelSignal(AtomicBoolean cancelSignal) {
|
||||
mCancelSignal = cancelSignal;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Throw early when cancellation is requested to avoid partial outputs.
|
||||
// zh-CN: 当收到取消请求时尽早抛出, 以避免产生部分输出.
|
||||
private void ensureNotCancelled() {
|
||||
if (mCancelSignal != null && mCancelSignal.get()) {
|
||||
throw new CancellationException("Build aborted");
|
||||
}
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new CancellationException("Build aborted");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void unzip() throws IOException {
|
||||
ZipInputStream zis = new ZipInputStream(mApkInputStream);
|
||||
for (ZipEntry e = zis.getNextEntry(); e != null; e = zis.getNextEntry()) {
|
||||
String name = e.getName();
|
||||
if (!e.isDirectory() && !TextUtils.isEmpty(name)) {
|
||||
File file = new File(mWorkspacePath, name);
|
||||
System.out.println(file);
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
StreamUtils.write(zis, fos);
|
||||
fos.close();
|
||||
// Buffer IO to reduce syscall overhead during APK extraction.
|
||||
// zh-CN: 使用缓冲 IO 以减少 APK 解压过程中的系统调用开销.
|
||||
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(mApkInputStream, StreamUtils.DEFAULT_BUFFER_SIZE))) {
|
||||
for (ZipEntry e = zis.getNextEntry(); e != null; e = zis.getNextEntry()) {
|
||||
ensureNotCancelled();
|
||||
String name = e.getName();
|
||||
if (!e.isDirectory() && !TextUtils.isEmpty(name)) {
|
||||
File file = new File(mWorkspacePath, name);
|
||||
File parentFile = file.getParentFile();
|
||||
if (parentFile != null) {
|
||||
parentFile.mkdirs();
|
||||
}
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), StreamUtils.DEFAULT_BUFFER_SIZE)) {
|
||||
byte[] buffer = new byte[StreamUtils.DEFAULT_BUFFER_SIZE];
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
ensureNotCancelled();
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
}
|
||||
|
||||
public void repackage(String newApkPath) throws Exception {
|
||||
|
||||
@@ -10,8 +10,10 @@ import java.io.OutputStream;
|
||||
*/
|
||||
public class StreamUtils {
|
||||
|
||||
public static final int DEFAULT_BUFFER_SIZE = 16 * 1024;
|
||||
|
||||
public static void write(InputStream inputStream, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
@@ -20,7 +22,7 @@ public class StreamUtils {
|
||||
|
||||
public static byte[] readAsBytes(InputStream inputStream) throws IOException {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, len);
|
||||
|
||||
@@ -4,8 +4,10 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
@@ -24,6 +26,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.flexbox.FlexboxLayout;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
@@ -35,14 +38,15 @@ import net.dongliu.apk.parser.bean.ApkMeta;
|
||||
import org.autojs.autojs.apkbuilder.ApkBuilder;
|
||||
import org.autojs.autojs.apkbuilder.keystore.KeyStore;
|
||||
import org.autojs.autojs.core.pref.Language;
|
||||
import org.autojs.autojs.util.DialogUtils;
|
||||
import org.autojs.autojs.external.fileprovider.AppFileProvider;
|
||||
import org.autojs.autojs.model.explorer.Explorers;
|
||||
import org.autojs.autojs.model.script.ScriptFile;
|
||||
import org.autojs.autojs.pio.PFiles;
|
||||
import org.autojs.autojs.project.ProjectConfig;
|
||||
import org.autojs.autojs.runtime.api.AppUtils;
|
||||
import org.autojs.autojs.runtime.api.AppUtils.Companion.SimpleVersionInfo;
|
||||
import org.autojs.autojs.runtime.api.augment.pinyin.Pinyin;
|
||||
import org.autojs.autojs.theme.ThemeColorManager;
|
||||
import org.autojs.autojs.ui.BaseActivity;
|
||||
import org.autojs.autojs.ui.common.NotAskAgainDialog;
|
||||
import org.autojs.autojs.ui.error.ErrorDialogActivity;
|
||||
@@ -55,13 +59,17 @@ import org.autojs.autojs.ui.widget.RoundCheckboxWithText;
|
||||
import org.autojs.autojs.util.AndroidUtils;
|
||||
import org.autojs.autojs.util.AndroidUtils.Abi;
|
||||
import org.autojs.autojs.util.BitmapUtils;
|
||||
import org.autojs.autojs.util.ColorUtils;
|
||||
import org.autojs.autojs.util.DialogUtils;
|
||||
import org.autojs.autojs.util.EnvironmentUtils;
|
||||
import org.autojs.autojs.util.IntentUtils;
|
||||
import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder;
|
||||
import org.autojs.autojs.util.StringUtils;
|
||||
import org.autojs.autojs.util.ViewUtils;
|
||||
import org.autojs.autojs.util.WorkingDirectoryUtils;
|
||||
import org.autojs.autojs6.R;
|
||||
import org.autojs.autojs6.databinding.ActivityBuildBinding;
|
||||
import org.autojs.autojs6.databinding.DialogBuildProgressBinding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
@@ -70,12 +78,14 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -89,7 +99,7 @@ import static org.autojs.autojs.util.StringUtils.key;
|
||||
* Created by Stardust on Oct 22, 2017.
|
||||
* Modified by SuperMonster003 as of Jan 6, 2026.
|
||||
*
|
||||
* @noinspection ResultOfMethodCallIgnored
|
||||
* @noinspection ResultOfMethodCallIgnored, unused
|
||||
*/
|
||||
public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCallback {
|
||||
|
||||
@@ -224,6 +234,35 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
|
||||
private ProjectConfig mProjectConfig;
|
||||
|
||||
private MaterialDialog mProgressDialog;
|
||||
private ImageView mProgressPrepareIcon;
|
||||
private TextView mProgressPrepareText;
|
||||
private ImageView mProgressBuildIcon;
|
||||
private TextView mProgressBuildText;
|
||||
private ImageView mProgressSignIcon;
|
||||
private TextView mProgressSignText;
|
||||
private ImageView mProgressCleanIcon;
|
||||
private TextView mProgressCleanText;
|
||||
private TextView mProgressPrepareDurationText;
|
||||
private TextView mProgressBuildDurationText;
|
||||
private TextView mProgressSignDurationText;
|
||||
private TextView mProgressCleanDurationText;
|
||||
private TextView mStateTitleText;
|
||||
private TextView mStateContentText;
|
||||
private final EnumMap<BuildStep, Long> mStepDurationMs = new EnumMap<>(BuildStep.class);
|
||||
@Nullable
|
||||
private BuildStep mCurrentTimingStep;
|
||||
private long mCurrentTimingStepStartedAtMs;
|
||||
// Track cancellation state for cooperative build abort.
|
||||
// zh-CN: 跟踪取消状态, 用于协作式中止构建.
|
||||
private final AtomicBoolean mBuildCancelled = new AtomicBoolean(false);
|
||||
@Nullable
|
||||
private File mBuildWorkspace;
|
||||
@Nullable
|
||||
private File mBuildOutputApk;
|
||||
@Nullable
|
||||
private File mBuildOutputApkBackup;
|
||||
@Nullable
|
||||
private Thread mBuildThread;
|
||||
private String mSource;
|
||||
private boolean mIsDefaultIcon = true;
|
||||
private boolean mIsProjectLevelBuilding;
|
||||
@@ -712,7 +751,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
protected void onNewIntent(@NonNull Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@@ -910,18 +949,40 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
|
||||
block == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@SuppressLint("CheckResult")
|
||||
private void doBuildingApk() {
|
||||
ProjectConfig projectConfig = determineProjectConfig();
|
||||
File buildPath = new File(getCacheDir(), "build/");
|
||||
File outApk = new File(mOutputPathView.getText().toString(),
|
||||
String.format("%s_v%s.apk", projectConfig.getName(), projectConfig.getVersionName()));
|
||||
File outApkBackup = null;
|
||||
try {
|
||||
outApkBackup = backupExistingOutputApkIfNeeded(outApk);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Failed to backup existing output apk", e);
|
||||
ErrorDialogActivity.showErrorDialog(this, R.string.text_failed_to_build, e.getMessage());
|
||||
return;
|
||||
}
|
||||
mBuildCancelled.set(false);
|
||||
mBuildWorkspace = buildPath;
|
||||
mBuildOutputApk = outApk;
|
||||
mBuildOutputApkBackup = outApkBackup;
|
||||
showProgressDialog();
|
||||
Observable.fromCallable(() -> callApkBuilder(buildPath, outApk, projectConfig))
|
||||
Observable.fromCallable(() -> {
|
||||
mBuildThread = Thread.currentThread();
|
||||
try {
|
||||
return callApkBuilder(buildPath, outApk, projectConfig);
|
||||
} finally {
|
||||
mBuildThread = null;
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(apkBuilder -> {
|
||||
if (mBuildCancelled.get()) {
|
||||
handleBuildAborted();
|
||||
return;
|
||||
}
|
||||
if (apkBuilder != null) {
|
||||
onBuildSuccessful(outApk);
|
||||
} else {
|
||||
@@ -930,6 +991,34 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
|
||||
}, this::onBuildFailed);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private File backupExistingOutputApkIfNeeded(@NonNull File outApk) throws IOException {
|
||||
if (!outApk.exists()) {
|
||||
return null;
|
||||
}
|
||||
File parentDir = outApk.getAbsoluteFile().getParentFile();
|
||||
if (parentDir == null) {
|
||||
throw new IOException("Invalid output apk path: " + outApk.getPath());
|
||||
}
|
||||
File backupApk = new File(parentDir, outApk.getName() + "." + System.nanoTime() + ".bak");
|
||||
if (backupApk.exists() && !backupApk.delete()) {
|
||||
throw new IOException("Failed to remove stale output apk backup: " + backupApk.getPath());
|
||||
}
|
||||
if (outApk.renameTo(backupApk)) {
|
||||
return backupApk;
|
||||
}
|
||||
if (!PFiles.copy(outApk.getPath(), backupApk.getPath())) {
|
||||
throw new IOException("Failed to backup existing output apk: " + outApk.getPath());
|
||||
}
|
||||
if (!outApk.delete()) {
|
||||
if (!backupApk.delete()) {
|
||||
Log.w(LOG_TAG, "Failed to delete incomplete backup apk after backup cleanup failure: " + backupApk.getPath());
|
||||
}
|
||||
throw new IOException("Failed to remove original output apk after backup copy: " + outApk.getPath());
|
||||
}
|
||||
return backupApk;
|
||||
}
|
||||
|
||||
private ProjectConfig determineProjectConfig() {
|
||||
ArrayList<String> abis = collectCheckedItems(mFlexboxAbisView);
|
||||
ArrayList<String> libs = collectCheckedItems(mFlexboxLibsView);
|
||||
@@ -988,71 +1077,362 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
|
||||
InputStream templateApk = getAssets().open(TEMPLATE_APK_NAME);
|
||||
return new ApkBuilder(templateApk, outApk, buildPath.getPath())
|
||||
.setProgressCallback(BuildActivity.this)
|
||||
.prepare()
|
||||
.withConfig(projectConfig)
|
||||
.build()
|
||||
.sign()
|
||||
.cleanWorkspace();
|
||||
.setCancelSignal(mBuildCancelled)
|
||||
.prepare(BuildActivity.this)
|
||||
.withConfig(BuildActivity.this, projectConfig)
|
||||
.build(BuildActivity.this)
|
||||
.sign(BuildActivity.this)
|
||||
.commitProjectConfigIfNeeded(BuildActivity.this)
|
||||
.cleanWorkspace(BuildActivity.this)
|
||||
.finish();
|
||||
}
|
||||
|
||||
private enum BuildStep {
|
||||
PREPARE,
|
||||
BUILD,
|
||||
SIGN,
|
||||
CLEAN,
|
||||
FINISHED,
|
||||
}
|
||||
|
||||
private void showProgressDialog() {
|
||||
dismissProgressDialog();
|
||||
View contentView = DialogBuildProgressBinding.inflate(getLayoutInflater()).getRoot();
|
||||
mProgressPrepareIcon = contentView.findViewById(R.id.icon_prepare);
|
||||
mProgressPrepareText = contentView.findViewById(R.id.text_prepare);
|
||||
mProgressBuildIcon = contentView.findViewById(R.id.icon_build);
|
||||
mProgressBuildText = contentView.findViewById(R.id.text_build);
|
||||
mProgressSignIcon = contentView.findViewById(R.id.icon_sign);
|
||||
mProgressSignText = contentView.findViewById(R.id.text_sign);
|
||||
mProgressCleanIcon = contentView.findViewById(R.id.icon_clean);
|
||||
mProgressCleanText = contentView.findViewById(R.id.text_clean);
|
||||
mProgressPrepareDurationText = contentView.findViewById(R.id.text_prepare_duration);
|
||||
mProgressBuildDurationText = contentView.findViewById(R.id.text_build_duration);
|
||||
mProgressSignDurationText = contentView.findViewById(R.id.text_sign_duration);
|
||||
mProgressCleanDurationText = contentView.findViewById(R.id.text_clean_duration);
|
||||
mStateTitleText = contentView.findViewById(R.id.text_state_title);
|
||||
mStateContentText = contentView.findViewById(R.id.text_state_content);
|
||||
resetStepDurations();
|
||||
applyThemeColorIcons(mProgressPrepareIcon, mProgressBuildIcon, mProgressSignIcon, mProgressCleanIcon);
|
||||
mProgressDialog = new MaterialDialog.Builder(this)
|
||||
.progress(true, 100)
|
||||
.content(R.string.text_in_progress)
|
||||
.title(R.string.text_building_apk)
|
||||
.customView(contentView, false)
|
||||
.neutralText("")
|
||||
.negativeText("")
|
||||
.positiveText(R.string.dialog_button_abort)
|
||||
.positiveColorRes(R.color.dialog_button_caution)
|
||||
.onPositive((dialog, which) -> requestBuildAbort())
|
||||
.autoDismiss(false)
|
||||
.cancelable(false)
|
||||
.show();
|
||||
updateProgressDialog(BuildStep.PREPARE);
|
||||
mStateTitleText.setText(getString(R.string.text_property_colon, getString(R.string.text_processing)));
|
||||
}
|
||||
|
||||
private void applyThemeColorIcons(ImageView... imageView) {
|
||||
int backgroundColor = getColor(R.color.window_background);
|
||||
int adjustedColor = ColorUtils.adjustColorForContrast(backgroundColor, ThemeColorManager.getColorPrimary(), 2.3);
|
||||
for (ImageView iv : imageView) {
|
||||
iv.setImageTintList(ColorStateList.valueOf(adjustedColor));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressDialog(BuildStep currentStep) {
|
||||
if (mProgressDialog == null) {
|
||||
return;
|
||||
}
|
||||
recordStepDuration(currentStep);
|
||||
setProgressStep(mProgressPrepareIcon, mProgressPrepareText, mProgressPrepareDurationText, BuildStep.PREPARE, currentStep);
|
||||
setProgressStep(mProgressBuildIcon, mProgressBuildText, mProgressBuildDurationText, BuildStep.BUILD, currentStep);
|
||||
setProgressStep(mProgressSignIcon, mProgressSignText, mProgressSignDurationText, BuildStep.SIGN, currentStep);
|
||||
setProgressStep(mProgressCleanIcon, mProgressCleanText, mProgressCleanDurationText, BuildStep.CLEAN, currentStep);
|
||||
}
|
||||
|
||||
private void setProgressStep(@Nullable ImageView iconView, @Nullable TextView stateView, @Nullable TextView durationView, BuildStep step, BuildStep currentStep) {
|
||||
if (step.ordinal() < currentStep.ordinal()) {
|
||||
if (iconView != null) iconView.setImageResource(R.drawable.ic_check_mark);
|
||||
if (stateView != null) stateView.setText(ensureTextEndsWithDot(stateView.getText()));
|
||||
if (durationView != null && currentStep.ordinal() - step.ordinal() == 1) {
|
||||
updateStepDurationText(durationView, step, SystemClock.elapsedRealtime());
|
||||
}
|
||||
} else if (step == currentStep) {
|
||||
if (iconView != null) iconView.setImageResource(R.drawable.ic_right_arrow);
|
||||
if (stateView != null) stateView.setText(ensureTextEndsWithHalfEllipsis(stateView.getText()));
|
||||
} else {
|
||||
if (iconView != null) iconView.setImageResource(R.drawable.transparent);
|
||||
if (stateView != null) stateView.setText(ensureTextEndsWithoutDot(stateView.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
private void resetStepDurations() {
|
||||
mStepDurationMs.clear();
|
||||
mCurrentTimingStep = null;
|
||||
mCurrentTimingStepStartedAtMs = 0L;
|
||||
}
|
||||
|
||||
private void recordStepDuration(@NonNull BuildStep currentStep) {
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
if (mCurrentTimingStep != null && mCurrentTimingStep != currentStep && isTrackedStep(mCurrentTimingStep)) {
|
||||
mStepDurationMs.put(mCurrentTimingStep, Math.max(0L, now - mCurrentTimingStepStartedAtMs));
|
||||
}
|
||||
if (isTrackedStep(currentStep) && !mStepDurationMs.containsKey(currentStep)) {
|
||||
if (mCurrentTimingStep != currentStep) {
|
||||
mCurrentTimingStep = currentStep;
|
||||
mCurrentTimingStepStartedAtMs = now;
|
||||
}
|
||||
} else if (!isTrackedStep(currentStep)) {
|
||||
mCurrentTimingStep = null;
|
||||
mCurrentTimingStepStartedAtMs = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTrackedStep(@NonNull BuildStep step) {
|
||||
return step == BuildStep.PREPARE
|
||||
|| step == BuildStep.BUILD
|
||||
|| step == BuildStep.SIGN
|
||||
|| step == BuildStep.CLEAN;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Long resolveStepDurationMs(@NonNull BuildStep step, long now) {
|
||||
Long duration = mStepDurationMs.get(step);
|
||||
if (duration != null) {
|
||||
return duration;
|
||||
}
|
||||
if (step == mCurrentTimingStep) {
|
||||
return Math.max(0L, now - mCurrentTimingStepStartedAtMs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateStepDurationText(@NonNull TextView textView, @NonNull BuildStep step, long now) {
|
||||
Long durationMs = resolveStepDurationMs(step, now);
|
||||
textView.setText(durationMs == null ? "" : formatStepDuration(durationMs));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String formatStepDuration(long durationMs) {
|
||||
long safeDurationMs = Math.max(0L, durationMs);
|
||||
long tenths = Math.round(safeDurationMs / 100.0d);
|
||||
long integerPart = tenths / 10;
|
||||
long decimalPart = tenths % 10;
|
||||
// if (decimalPart == 0L) {
|
||||
// return "[ " + integerPart + " s ]";
|
||||
// }
|
||||
return "[ " + integerPart + "." + decimalPart + " s ]";
|
||||
}
|
||||
|
||||
private String ensureTextEndsWithDot(CharSequence text) {
|
||||
return ensureTextEndsWithoutDot(text) + ".";
|
||||
}
|
||||
|
||||
private String ensureTextEndsWithHalfEllipsis(CharSequence text) {
|
||||
return ensureTextEndsWithoutDot(text) + StringUtils.str(R.string.text_half_ellipsis);
|
||||
}
|
||||
|
||||
private String ensureTextEndsWithoutDot(CharSequence text) {
|
||||
var tmp = text.toString();
|
||||
while (tmp.length() > 0 && tmp.charAt(tmp.length() - 1) == '.') {
|
||||
tmp = tmp.subSequence(0, tmp.length() - 1).toString();
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Abort build cooperatively and trigger cleanup as early as possible.
|
||||
// zh-CN: 协作式中止构建, 并尽早触发清理.
|
||||
private void requestBuildAbort() {
|
||||
if (!mBuildCancelled.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.setTitle(R.string.text_aborting);
|
||||
View button = mProgressDialog.getActionButton(DialogAction.POSITIVE);
|
||||
if (button != null) {
|
||||
button.setEnabled(false);
|
||||
}
|
||||
}
|
||||
Thread buildThread = mBuildThread;
|
||||
if (buildThread != null) {
|
||||
buildThread.interrupt();
|
||||
}
|
||||
cleanupBuildArtifactsAsync(false);
|
||||
}
|
||||
|
||||
private void cleanupBuildArtifactsAsync(boolean restoreOutputApk) {
|
||||
File workspace = mBuildWorkspace;
|
||||
File outApk = mBuildOutputApk;
|
||||
File outApkBackup = mBuildOutputApkBackup;
|
||||
if (workspace == null && outApk == null && outApkBackup == null) {
|
||||
return;
|
||||
}
|
||||
Schedulers.io().scheduleDirect(() -> cleanupBuildArtifacts(workspace, outApk, outApkBackup, restoreOutputApk));
|
||||
}
|
||||
|
||||
// Best-effort cleanup for workspace and output artifacts.
|
||||
// zh-CN: 对工作区和输出产物执行尽力清理.
|
||||
private void cleanupBuildArtifacts(@Nullable File workspace, @Nullable File outApk, @Nullable File outApkBackup, boolean restoreOutputApk) {
|
||||
if (workspace != null && workspace.exists()) {
|
||||
PFiles.deleteRecursively(workspace);
|
||||
}
|
||||
if (outApk != null && outApk.exists()) {
|
||||
outApk.delete();
|
||||
}
|
||||
if (restoreOutputApk) {
|
||||
restoreOutputApkIfNeeded(outApk, outApkBackup);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreOutputApkIfNeeded(@Nullable File outApk, @Nullable File outApkBackup) {
|
||||
if (outApk == null || outApkBackup == null || !outApkBackup.exists()) {
|
||||
return;
|
||||
}
|
||||
if (outApk.exists() && !outApk.delete()) {
|
||||
Log.w(LOG_TAG, "Failed to delete output apk before restore: " + outApk.getPath());
|
||||
}
|
||||
if (!outApkBackup.renameTo(outApk)) {
|
||||
if (!PFiles.copy(outApkBackup.getPath(), outApk.getPath())) {
|
||||
Log.w(LOG_TAG, "Failed to restore output apk backup: " + outApk.getPath());
|
||||
return;
|
||||
}
|
||||
if (!outApkBackup.delete()) {
|
||||
Log.w(LOG_TAG, "Failed to delete output apk backup: " + outApkBackup.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void discardOutputApkBackup() {
|
||||
File outApkBackup = mBuildOutputApkBackup;
|
||||
if (outApkBackup != null && outApkBackup.exists() && !outApkBackup.delete()) {
|
||||
Log.w(LOG_TAG, "Failed to delete output apk backup: " + outApkBackup.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBuildAborted() {
|
||||
dismissProgressDialog();
|
||||
cleanupBuildArtifactsAsync(true);
|
||||
ViewUtils.showToast(this, getString(R.string.text_operation_aborted));
|
||||
finishBuildState();
|
||||
}
|
||||
|
||||
private void finishBuildState() {
|
||||
mBuildWorkspace = null;
|
||||
mBuildOutputApk = null;
|
||||
mBuildOutputApkBackup = null;
|
||||
mBuildThread = null;
|
||||
mBuildCancelled.set(false);
|
||||
}
|
||||
|
||||
private void dismissProgressDialog() {
|
||||
if (mProgressDialog == null) {
|
||||
return;
|
||||
}
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
mProgressPrepareIcon = null;
|
||||
mProgressPrepareText = null;
|
||||
mProgressBuildIcon = null;
|
||||
mProgressBuildText = null;
|
||||
mProgressSignIcon = null;
|
||||
mProgressSignText = null;
|
||||
mProgressCleanIcon = null;
|
||||
mProgressCleanText = null;
|
||||
mProgressPrepareDurationText = null;
|
||||
mProgressBuildDurationText = null;
|
||||
mProgressSignDurationText = null;
|
||||
mProgressCleanDurationText = null;
|
||||
mStateTitleText = null;
|
||||
mStateContentText = null;
|
||||
resetStepDurations();
|
||||
}
|
||||
|
||||
private void onBuildFailed(Throwable error) {
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
if (mBuildCancelled.get() || error instanceof CancellationException) {
|
||||
handleBuildAborted();
|
||||
return;
|
||||
}
|
||||
dismissProgressDialog();
|
||||
restoreOutputApkIfNeeded(mBuildOutputApk, mBuildOutputApkBackup);
|
||||
ErrorDialogActivity.showErrorDialog(this, R.string.text_failed_to_build, error.getMessage());
|
||||
Log.e(LOG_TAG, "Failed to build", error);
|
||||
finishBuildState();
|
||||
}
|
||||
|
||||
private void onBuildSuccessful(File outApk) {
|
||||
if (mBuildCancelled.get()) {
|
||||
handleBuildAborted();
|
||||
return;
|
||||
}
|
||||
discardOutputApkBackup();
|
||||
Explorers.workspace().refreshAll();
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.text_build_succeeded)
|
||||
.content(getString(R.string.format_build_succeeded, outApk.getPath()))
|
||||
.positiveText(R.string.text_install)
|
||||
.positiveColorRes(R.color.dialog_button_attraction)
|
||||
.onPositive((dialog, which) -> IntentUtils.installApk(
|
||||
// dismissProgressDialog();
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.setTitle(R.string.text_build_succeeded);
|
||||
mStateTitleText.setText(getString(R.string.text_property_colon, getString(R.string.text_built_apk_file_path)));
|
||||
mStateContentText.setText(outApk.getPath());
|
||||
var positiveButton = mProgressDialog.getActionButton(DialogAction.POSITIVE);
|
||||
positiveButton.setEnabled(true);
|
||||
positiveButton.setText(getString(R.string.text_install));
|
||||
positiveButton.setTextColor(getColor(R.color.dialog_button_attraction));
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
IntentUtils.installApk(
|
||||
BuildActivity.this,
|
||||
outApk.getPath(),
|
||||
AppFileProvider.AUTHORITY,
|
||||
new ToastExceptionHolder(BuildActivity.this)
|
||||
))
|
||||
.negativeText(R.string.text_cancel)
|
||||
.negativeColorRes(R.color.dialog_button_default)
|
||||
.neutralText(R.string.dialog_button_file_information)
|
||||
.neutralColorRes(R.color.dialog_button_hint)
|
||||
.onNeutral((dialog, which) -> ApkInfoDialogManager.showApkInfoDialog(dialog.getContext(), outApk))
|
||||
.show();
|
||||
);
|
||||
dismissProgressDialog();
|
||||
});
|
||||
var negativeButton = mProgressDialog.getActionButton(DialogAction.NEGATIVE);
|
||||
negativeButton.setEnabled(true);
|
||||
negativeButton.setText(getString(R.string.text_cancel));
|
||||
negativeButton.setTextColor(getColor(R.color.dialog_button_default));
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
dismissProgressDialog();
|
||||
});
|
||||
var neutralButton = mProgressDialog.getActionButton(DialogAction.NEUTRAL);
|
||||
neutralButton.setEnabled(true);
|
||||
neutralButton.setText(getString(R.string.dialog_button_file_information));
|
||||
neutralButton.setTextColor(getColor(R.color.dialog_button_hint));
|
||||
neutralButton.setOnClickListener(v -> {
|
||||
ApkInfoDialogManager.showApkInfoDialog(this, outApk);
|
||||
});
|
||||
}
|
||||
finishBuildState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepare(@NonNull ApkBuilder builder) {
|
||||
mProgressDialog.setContent(R.string.apk_builder_prepare);
|
||||
updateProgressDialog(BuildStep.PREPARE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBuild(@NonNull ApkBuilder builder) {
|
||||
mProgressDialog.setContent(R.string.apk_builder_build);
|
||||
updateProgressDialog(BuildStep.BUILD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSign(@NonNull ApkBuilder builder) {
|
||||
mProgressDialog.setContent(R.string.apk_builder_package);
|
||||
updateProgressDialog(BuildStep.SIGN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClean(@NonNull ApkBuilder builder) {
|
||||
mProgressDialog.setContent(R.string.apk_builder_clean);
|
||||
updateProgressDialog(BuildStep.CLEAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStepProgress(@NonNull ApkBuilder builder, @NonNull String title, @Nullable String detail) {
|
||||
if (mStateTitleText != null) {
|
||||
mStateTitleText.setText(getString(R.string.text_property_colon, title));
|
||||
}
|
||||
if (!TextUtils.isEmpty(detail) && mStateContentText != null) {
|
||||
mStateContentText.setText(detail);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(@NotNull ApkBuilder builder) {
|
||||
updateProgressDialog(BuildStep.FINISHED);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
|
||||
BIN
app/src/main/res/drawable/ic_check_mark.png
Normal file
BIN
app/src/main/res/drawable/ic_check_mark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
BIN
app/src/main/res/drawable/ic_right_arrow.png
Normal file
BIN
app/src/main/res/drawable/ic_right_arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
186
app/src/main/res/layout/dialog_build_progress.xml
Normal file
186
app/src/main/res/layout/dialog_build_progress.xml
Normal file
@@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="@dimen/ref_md_dialog_frame_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/build_progress_row_spacing"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_prepare"
|
||||
android:layout_width="@dimen/build_progress_icon_size"
|
||||
android:layout_height="@dimen/build_progress_icon_size"
|
||||
tools:src="@drawable/ic_check_mark"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_prepare"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/build_progress_icon_text_gap"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
android:text="@string/text_prepare" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_prepare_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:minEms="8"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="[ 0.3 s ]" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/build_progress_row_spacing"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_build"
|
||||
android:layout_width="@dimen/build_progress_icon_size"
|
||||
android:layout_height="@dimen/build_progress_icon_size"
|
||||
tools:src="@drawable/ic_check_mark"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_build"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/build_progress_icon_text_gap"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
android:text="@string/text_build" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_build_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:minEms="8"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="[ 10.7 s ]" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/build_progress_row_spacing"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_sign"
|
||||
android:layout_width="@dimen/build_progress_icon_size"
|
||||
android:layout_height="@dimen/build_progress_icon_size"
|
||||
tools:src="@drawable/ic_check_mark"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sign"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/build_progress_icon_text_gap"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
android:text="@string/text_sign" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sign_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:minEms="8"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="[ 23 s ]" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/build_progress_row_spacing"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_clean"
|
||||
android:layout_width="@dimen/build_progress_icon_size"
|
||||
android:layout_height="@dimen/build_progress_icon_size"
|
||||
tools:src="@drawable/ic_check_mark"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_clean"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/build_progress_icon_text_gap"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
android:text="@string/text_clean" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_clean_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:minEms="8"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="[ 0.1 s ]" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_marginVertical="@dimen/build_progress_row_spacing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_state_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="middle"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="@string/text_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_state_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:gravity="top"
|
||||
android:lines="2"
|
||||
android:maxLines="2"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:ellipsize="end"
|
||||
android:textSize="@dimen/build_progress_icon_text_size"
|
||||
tools:text="@string/text_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -9,11 +9,11 @@
|
||||
<!-- Proofreader: [ Google Gemini ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">مبنى...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">تنظيف...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">التغليف ...</string>
|
||||
<string name="apk_builder_build">مبنى</string>
|
||||
<string name="apk_builder_clean">تنظيف</string>
|
||||
<string name="apk_builder_package">التغليف </string>
|
||||
<string name="apk_builder_plugin_version_incompatible">نسخة غير متوافقة من \"APK Builder\".\nتحميله الآن؟</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">خطة...</string>
|
||||
<string name="apk_builder_prepare">خطة</string>
|
||||
<string name="apk_info_device_sdk">SDK الجهاز</string>
|
||||
<string name="apk_info_file_size">حجم الملف</string>
|
||||
<string name="apk_info_installed_version">مثبت</string>
|
||||
@@ -536,7 +536,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">توثيق</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 سجل</string>
|
||||
<string name="text_app_shortcut_log_short_label">سجل</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">مركز اضافات AutoJs6</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 الاضافات</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">الاضافات</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 إعدادات</string>
|
||||
<string name="text_app_shortcut_settings_short_label">إعدادات</string>
|
||||
@@ -674,7 +674,7 @@
|
||||
<string name="text_delete_folder">حذف المجلد</string>
|
||||
<string name="text_delete_line">حذف الخط</string>
|
||||
<string name="text_delete_revision_confirm">هل تريد حذف هذه المراجعة نهائيا?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">جارٍ الحذف...</string>
|
||||
<string name="text_deleting">جارٍ الحذف</string>
|
||||
<string name="text_description">الوصف</string>
|
||||
<string name="text_deselect_all">الغاء التحديد</string>
|
||||
<string name="text_destination">الوجهة</string>
|
||||
@@ -1086,7 +1086,7 @@
|
||||
<string name="text_press_back_or_vol_down_to_close_window">لإغلاق، اضغط على \"رجوع\" أو \"خفض الصوت\"</string>
|
||||
<string name="text_preview">معاينة</string>
|
||||
<string name="text_process_log">سجل العملية</string>
|
||||
<string name="text_processing">يعالج</string>
|
||||
<string name="text_processing">جارٍ المعالجة</string>
|
||||
<string name="text_project">مشروع</string>
|
||||
<string name="text_project_location">موقع المشروع</string>
|
||||
<string name="text_project_media_access">وصول وسائل الإعلام المشروع</string>
|
||||
@@ -1358,4 +1358,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">الاضافة \"%1$s\" غير مُفوّضة في مركز الاضافات</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">لم يتم العثور على الاضافة \"%1$s\" ضمن التطبيقات المثبتة</string>
|
||||
<string name="error_unsupported_plugin_connection">طريقة اتصال الاضافة غير مدعومة</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">العنوان</string>
|
||||
<string name="text_content">المحتوى</string>
|
||||
<string name="text_building_apk">جارٍ بناء APK</string>
|
||||
<string name="text_built_apk_file_path">مسار APK المبني</string>
|
||||
<string name="text_clean">تنظيف</string>
|
||||
<string name="text_sign">توقيع</string>
|
||||
<string name="text_build">بناء</string>
|
||||
<string name="text_prepare">تحضير</string>
|
||||
<string name="text_preparing_workspace">جارٍ تحضير مساحة العمل</string>
|
||||
<string name="text_extracting_template_apk">جارٍ استخراج APK القالب</string>
|
||||
<string name="text_prepare_completed">اكتمل التحضير</string>
|
||||
<string name="text_copying_project_directory">جارٍ نسخ مجلد المشروع</string>
|
||||
<string name="text_copying_script_file">جارٍ نسخ ملف السكربت</string>
|
||||
<string name="text_source_processing_completed">اكتملت معالجة المصدر</string>
|
||||
<string name="text_copying_directory">جارٍ نسخ المجلد</string>
|
||||
<string name="text_copying_file">جارٍ نسخ الملف</string>
|
||||
<string name="text_encrypting_script">جارٍ تشفير السكربت</string>
|
||||
<string name="text_replacing_file">جارٍ استبدال الملف</string>
|
||||
<string name="text_preparing_build_config">جارٍ تحضير اعدادات البناء</string>
|
||||
<string name="text_reading_splash_resources">جارٍ قراءة موارد شاشة البدء</string>
|
||||
<string name="text_configuring_manifest">جارٍ ضبط manifest</string>
|
||||
<string name="text_configuring_package_name">جارٍ ضبط اسم الحزمة</string>
|
||||
<string name="text_copying_assets_to">جارٍ نسخ assets الى</string>
|
||||
<string name="text_processing_source">جارٍ معالجة المصدر</string>
|
||||
<string name="text_applying_binary_resources">جارٍ تطبيق الموارد الثنائية</string>
|
||||
<string name="text_copying_native_libraries">جارٍ نسخ المكتبات الاصلية</string>
|
||||
<string name="text_updating_project_config">جارٍ تحديث اعدادات المشروع</string>
|
||||
<string name="text_sign_stage_completed">اكتملت مرحلة التوقيع</string>
|
||||
<string name="text_writing_project_config">جارٍ كتابة اعدادات المشروع</string>
|
||||
<string name="text_building_resources">جارٍ بناء الموارد</string>
|
||||
<string name="text_build_completed">اكتمل البناء</string>
|
||||
<string name="text_writing_resources_arsc">جارٍ كتابة resources.arsc</string>
|
||||
<string name="text_writing_manifest">جارٍ كتابة manifest</string>
|
||||
<string name="text_writing_app_icon">جارٍ كتابة ايقونة التطبيق</string>
|
||||
<string name="text_copying_asset">جارٍ نسخ asset</string>
|
||||
<string name="text_preparing_assets_dir">جارٍ تحضير مجلد assets</string>
|
||||
<string name="text_copying_library">جارٍ نسخ المكتبة</string>
|
||||
<string name="text_preparing_keystore">جارٍ تحضير keystore</string>
|
||||
<string name="text_unsigned_apk_created">تم انشاء APK غير موقّع</string>
|
||||
<string name="text_creating_unsigned_apk">جارٍ انشاء APK غير موقّع</string>
|
||||
<string name="text_using_keystore">جارٍ استخدام keystore</string>
|
||||
<string name="text_re_signing_apk">جارٍ اعادة توقيع APK</string>
|
||||
<string name="text_writing_signed_apk">جارٍ كتابة APK الموقّع</string>
|
||||
<string name="text_sign_completed">اكتمل التوقيع</string>
|
||||
<string name="text_clean_completed">اكتمل التنظيف</string>
|
||||
<string name="text_cleaning_workspace">جارٍ تنظيف مساحة العمل</string>
|
||||
<string name="text_resolving_plugin_native_libraries">جارٍ تحليل مكتبات الاضافة الاصلية</string>
|
||||
<string name="text_copying_libraries_for_abi">جارٍ نسخ المكتبات لـ ABI</string>
|
||||
<string name="text_selected_plugin">الاضافة المحددة</string>
|
||||
<string name="text_extracted_plugin_libraries">تم استخراج مكتبات الاضافة</string>
|
||||
<string name="text_extracted_plugin_assets">تم استخراج assets الاضافة</string>
|
||||
<string name="text_extracting_plugin_asset">جارٍ استخراج asset الاضافة</string>
|
||||
<string name="text_extracting_plugin_so">جارٍ استخراج ملف so للاضافة</string>
|
||||
</resources>
|
||||
@@ -4,11 +4,11 @@
|
||||
<!-- Proofreader: [ SuperMonster003 ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">Building...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">Cleaning...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">Packaging...</string>
|
||||
<string name="apk_builder_build">Building</string>
|
||||
<string name="apk_builder_clean">Cleaning</string>
|
||||
<string name="apk_builder_package">Packaging</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">Incompatible version of \"apk builder\".\nDownload it now?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">Preparing...</string>
|
||||
<string name="apk_builder_prepare">Preparing</string>
|
||||
<string name="apk_info_device_sdk">Device SDK</string>
|
||||
<string name="apk_info_file_size">File size</string>
|
||||
<string name="apk_info_installed_version">Installed</string>
|
||||
@@ -531,7 +531,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">Docs</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 Log</string>
|
||||
<string name="text_app_shortcut_log_short_label">Log</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugin Center</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugins</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">Plugins</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 Settings</string>
|
||||
<string name="text_app_shortcut_settings_short_label">Settings</string>
|
||||
@@ -669,7 +669,7 @@
|
||||
<string name="text_delete_folder">Delete folder</string>
|
||||
<string name="text_delete_line">Delete line</string>
|
||||
<string name="text_delete_revision_confirm">Delete this revision permanently?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">Deleting...</string>
|
||||
<string name="text_deleting">Deleting</string>
|
||||
<string name="text_description">Description</string>
|
||||
<string name="text_deselect_all">Deselect all</string>
|
||||
<string name="text_destination">Destination</string>
|
||||
@@ -772,7 +772,7 @@
|
||||
<string name="text_file_name">File name</string>
|
||||
<string name="text_file_name_colon_value">File name: %1$s</string>
|
||||
<string name="text_file_not_exists">File does not exist</string>
|
||||
<string name="text_file_path">File Path</string>
|
||||
<string name="text_file_path">File path</string>
|
||||
<string name="text_file_with_abs_path_is_not_an_executable_script">File \"%1$s\" is not an executable script</string>
|
||||
<string name="text_filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="text_filename_cannot_contain_invalid_character">Filename cannot contain the following characters: \\ / : * ? " < > |</string>
|
||||
@@ -1353,4 +1353,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">Plugin \"%1$s\" is not authorized in Plugin Center</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">Plugin \"%1$s\" not found in installed apps</string>
|
||||
<string name="error_unsupported_plugin_connection">Unsupported plugin connection</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">Title</string>
|
||||
<string name="text_content">Content</string>
|
||||
<string name="text_building_apk">Building APK</string>
|
||||
<string name="text_built_apk_file_path">Built APK file path</string>
|
||||
<string name="text_clean">Clean</string>
|
||||
<string name="text_sign">Sign</string>
|
||||
<string name="text_build">Build</string>
|
||||
<string name="text_prepare">Prepare</string>
|
||||
<string name="text_preparing_workspace">Preparing workspace</string>
|
||||
<string name="text_extracting_template_apk">Extracting template APK</string>
|
||||
<string name="text_prepare_completed">Prepare completed</string>
|
||||
<string name="text_copying_project_directory">Copying project directory</string>
|
||||
<string name="text_copying_script_file">Copying script file</string>
|
||||
<string name="text_source_processing_completed">Source processing completed</string>
|
||||
<string name="text_copying_directory">Copying directory</string>
|
||||
<string name="text_copying_file">Copying file</string>
|
||||
<string name="text_encrypting_script">Encrypting script</string>
|
||||
<string name="text_replacing_file">Replacing file</string>
|
||||
<string name="text_preparing_build_config">Preparing build config</string>
|
||||
<string name="text_reading_splash_resources">Reading splash resources</string>
|
||||
<string name="text_configuring_manifest">Configuring manifest</string>
|
||||
<string name="text_configuring_package_name">Configuring package name</string>
|
||||
<string name="text_copying_assets_to">Copying assets to</string>
|
||||
<string name="text_processing_source">Processing source</string>
|
||||
<string name="text_applying_binary_resources">Applying binary resources</string>
|
||||
<string name="text_copying_native_libraries">Copying native libraries</string>
|
||||
<string name="text_updating_project_config">Updating project config</string>
|
||||
<string name="text_sign_stage_completed">Sign stage completed</string>
|
||||
<string name="text_writing_project_config">Writing project config</string>
|
||||
<string name="text_building_resources">Building resources</string>
|
||||
<string name="text_build_completed">Build completed</string>
|
||||
<string name="text_writing_resources_arsc">Writing resources.arsc</string>
|
||||
<string name="text_writing_manifest">Writing manifest</string>
|
||||
<string name="text_writing_app_icon">Writing app icon</string>
|
||||
<string name="text_copying_asset">Copying asset</string>
|
||||
<string name="text_preparing_assets_dir">Preparing assets dir</string>
|
||||
<string name="text_copying_library">Copying library</string>
|
||||
<string name="text_preparing_keystore">Preparing keystore</string>
|
||||
<string name="text_unsigned_apk_created">Unsigned APK created</string>
|
||||
<string name="text_creating_unsigned_apk">Creating unsigned APK</string>
|
||||
<string name="text_using_keystore">Using keystore</string>
|
||||
<string name="text_re_signing_apk">Re-signing APK</string>
|
||||
<string name="text_writing_signed_apk">Writing signed APK</string>
|
||||
<string name="text_sign_completed">Sign completed</string>
|
||||
<string name="text_clean_completed">Clean completed</string>
|
||||
<string name="text_cleaning_workspace">Cleaning workspace</string>
|
||||
<string name="text_resolving_plugin_native_libraries">Resolving plugin native libraries</string>
|
||||
<string name="text_copying_libraries_for_abi">Copying libraries for ABI</string>
|
||||
<string name="text_selected_plugin">Selected plugin</string>
|
||||
<string name="text_extracted_plugin_libraries">Extracted plugin libraries</string>
|
||||
<string name="text_extracted_plugin_assets">Extracted plugin assets</string>
|
||||
<string name="text_extracting_plugin_asset">Extracting plugin asset</string>
|
||||
<string name="text_extracting_plugin_so">Extracting plugin so</string>
|
||||
</resources>
|
||||
@@ -7,11 +7,11 @@
|
||||
<!-- Proofreader: [ JetBrains AI Assistant ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">Construir...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">Limpieza...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">Empaquetando...</string>
|
||||
<string name="apk_builder_build">Construir</string>
|
||||
<string name="apk_builder_clean">Limpieza</string>
|
||||
<string name="apk_builder_package">Empaquetando</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">Versión incompatible de \"apk builder\".\n¿Descargarlo ahora?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">Preparando...</string>
|
||||
<string name="apk_builder_prepare">Preparando</string>
|
||||
<string name="apk_info_device_sdk">SDK del dispositivo</string>
|
||||
<string name="apk_info_file_size">Tamaño de archivo</string>
|
||||
<string name="apk_info_installed_version">Instalado</string>
|
||||
@@ -534,7 +534,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">Docs</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 Registrar</string>
|
||||
<string name="text_app_shortcut_log_short_label">Registrar</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">Centro de plugins de AutoJs6</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugins</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">Plugins</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 Configuración</string>
|
||||
<string name="text_app_shortcut_settings_short_label">Configuración</string>
|
||||
@@ -672,7 +672,7 @@
|
||||
<string name="text_delete_folder">Eliminar carpeta</string>
|
||||
<string name="text_delete_line">Borrar línea</string>
|
||||
<string name="text_delete_revision_confirm">¿Eliminar esta revision de forma permanente?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">Eliminando...</string>
|
||||
<string name="text_deleting">Eliminando</string>
|
||||
<string name="text_description">Descripción</string>
|
||||
<string name="text_deselect_all">Deseleccionar todo</string>
|
||||
<string name="text_destination">Destino</string>
|
||||
@@ -1356,4 +1356,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">El plugin \"%1$s\" no esta autorizado en el Centro de plugins</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">No se encontro el plugin \"%1$s\" en las apps instaladas</string>
|
||||
<string name="error_unsupported_plugin_connection">Conexion de plugin no compatible</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">Titulo</string>
|
||||
<string name="text_content">Contenido</string>
|
||||
<string name="text_building_apk">Compilando APK</string>
|
||||
<string name="text_built_apk_file_path">Ruta del APK generado</string>
|
||||
<string name="text_clean">Limpiar</string>
|
||||
<string name="text_sign">Firmar</string>
|
||||
<string name="text_build">Compilar</string>
|
||||
<string name="text_prepare">Preparar</string>
|
||||
<string name="text_preparing_workspace">Preparando el espacio de trabajo</string>
|
||||
<string name="text_extracting_template_apk">Extrayendo APK plantilla</string>
|
||||
<string name="text_prepare_completed">Preparacion completada</string>
|
||||
<string name="text_copying_project_directory">Copiando directorio del proyecto</string>
|
||||
<string name="text_copying_script_file">Copiando archivo de script</string>
|
||||
<string name="text_source_processing_completed">Procesamiento del codigo fuente completado</string>
|
||||
<string name="text_copying_directory">Copiando directorio</string>
|
||||
<string name="text_copying_file">Copiando archivo</string>
|
||||
<string name="text_encrypting_script">Cifrando script</string>
|
||||
<string name="text_replacing_file">Reemplazando archivo</string>
|
||||
<string name="text_preparing_build_config">Preparando configuracion de compilacion</string>
|
||||
<string name="text_reading_splash_resources">Leyendo recursos de inicio</string>
|
||||
<string name="text_configuring_manifest">Configurando manifest</string>
|
||||
<string name="text_configuring_package_name">Configurando nombre de paquete</string>
|
||||
<string name="text_copying_assets_to">Copiando assets a</string>
|
||||
<string name="text_processing_source">Procesando codigo fuente</string>
|
||||
<string name="text_applying_binary_resources">Aplicando recursos binarios</string>
|
||||
<string name="text_copying_native_libraries">Copiando bibliotecas nativas</string>
|
||||
<string name="text_updating_project_config">Actualizando configuracion del proyecto</string>
|
||||
<string name="text_sign_stage_completed">Etapa de firma completada</string>
|
||||
<string name="text_writing_project_config">Escribiendo configuracion del proyecto</string>
|
||||
<string name="text_building_resources">Compilando recursos</string>
|
||||
<string name="text_build_completed">Compilacion completada</string>
|
||||
<string name="text_writing_resources_arsc">Escribiendo resources.arsc</string>
|
||||
<string name="text_writing_manifest">Escribiendo manifest</string>
|
||||
<string name="text_writing_app_icon">Escribiendo icono de la app</string>
|
||||
<string name="text_copying_asset">Copiando asset</string>
|
||||
<string name="text_preparing_assets_dir">Preparando dir de assets</string>
|
||||
<string name="text_copying_library">Copiando biblioteca</string>
|
||||
<string name="text_preparing_keystore">Preparando keystore</string>
|
||||
<string name="text_unsigned_apk_created">APK sin firmar creado</string>
|
||||
<string name="text_creating_unsigned_apk">Creando APK sin firmar</string>
|
||||
<string name="text_using_keystore">Usando keystore</string>
|
||||
<string name="text_re_signing_apk">Re-firmando APK</string>
|
||||
<string name="text_writing_signed_apk">Escribiendo APK firmado</string>
|
||||
<string name="text_sign_completed">Firma completada</string>
|
||||
<string name="text_clean_completed">Limpieza completada</string>
|
||||
<string name="text_cleaning_workspace">Limpiando el espacio de trabajo</string>
|
||||
<string name="text_resolving_plugin_native_libraries">Resolviendo bibliotecas nativas del plugin</string>
|
||||
<string name="text_copying_libraries_for_abi">Copiando bibliotecas para ABI</string>
|
||||
<string name="text_selected_plugin">Plugin seleccionado</string>
|
||||
<string name="text_extracted_plugin_libraries">Bibliotecas del plugin extraidas</string>
|
||||
<string name="text_extracted_plugin_assets">Assets del plugin extraidos</string>
|
||||
<string name="text_extracting_plugin_asset">Extrayendo asset del plugin</string>
|
||||
<string name="text_extracting_plugin_so">Extrayendo archivo so del plugin</string>
|
||||
</resources>
|
||||
@@ -7,11 +7,11 @@
|
||||
<!-- Proofreader : [ JetBrains AI Assistant ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">Construire...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">Nettoyage...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">Emballage...</string>
|
||||
<string name="apk_builder_build">Construire</string>
|
||||
<string name="apk_builder_clean">Nettoyage</string>
|
||||
<string name="apk_builder_package">Emballage</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">Version incompatible de \"apk builder\".\nTéléchargez-la maintenant ?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">Préparation...</string>
|
||||
<string name="apk_builder_prepare">Préparation</string>
|
||||
<string name="apk_info_device_sdk">SDK de l\'appareil</string>
|
||||
<string name="apk_info_file_size">Taille du fichier</string>
|
||||
<string name="apk_info_installed_version">Installé</string>
|
||||
@@ -534,7 +534,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">Docs</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 Journal</string>
|
||||
<string name="text_app_shortcut_log_short_label">Journal</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">Centre des plugins AutoJs6</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugins</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">Plugins</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 Réglages</string>
|
||||
<string name="text_app_shortcut_settings_short_label">Réglages</string>
|
||||
@@ -672,7 +672,7 @@
|
||||
<string name="text_delete_folder">Supprimer le dossier</string>
|
||||
<string name="text_delete_line">Supprimer la ligne</string>
|
||||
<string name="text_delete_revision_confirm">Supprimer definitivement cette revision?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">Suppression...</string>
|
||||
<string name="text_deleting">Suppression</string>
|
||||
<string name="text_description">Description</string>
|
||||
<string name="text_deselect_all">Tout deselectionner</string>
|
||||
<string name="text_destination">Destination</string>
|
||||
@@ -1356,4 +1356,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">Le plugin \"%1$s\" n\'est pas autorise dans le Centre des plugins</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">Plugin \"%1$s\" introuvable parmi les applis installees</string>
|
||||
<string name="error_unsupported_plugin_connection">Connexion de plugin non prise en charge</string>
|
||||
<string name="text_property_colon">%1$s :</string>
|
||||
<string name="text_title">Titre</string>
|
||||
<string name="text_content">Contenu</string>
|
||||
<string name="text_building_apk">Compilation de l\'APK</string>
|
||||
<string name="text_built_apk_file_path">Chemin de l\'APK genere</string>
|
||||
<string name="text_clean">Nettoyer</string>
|
||||
<string name="text_sign">Signer</string>
|
||||
<string name="text_build">Compiler</string>
|
||||
<string name="text_prepare">Preparer</string>
|
||||
<string name="text_preparing_workspace">Preparation de l\'espace de travail</string>
|
||||
<string name="text_extracting_template_apk">Extraction de l\'APK modele</string>
|
||||
<string name="text_prepare_completed">Preparation terminee</string>
|
||||
<string name="text_copying_project_directory">Copie du repertoire du projet</string>
|
||||
<string name="text_copying_script_file">Copie du fichier de script</string>
|
||||
<string name="text_source_processing_completed">Traitement du code source termine</string>
|
||||
<string name="text_copying_directory">Copie du repertoire</string>
|
||||
<string name="text_copying_file">Copie du fichier</string>
|
||||
<string name="text_encrypting_script">Chiffrement du script</string>
|
||||
<string name="text_replacing_file">Remplacement du fichier</string>
|
||||
<string name="text_preparing_build_config">Preparation de la config de build</string>
|
||||
<string name="text_reading_splash_resources">Lecture des ressources d\'ecran de demarrage</string>
|
||||
<string name="text_configuring_manifest">Configuration du manifest</string>
|
||||
<string name="text_configuring_package_name">Configuration du nom de package</string>
|
||||
<string name="text_copying_assets_to">Copie des assets vers</string>
|
||||
<string name="text_processing_source">Traitement du code source</string>
|
||||
<string name="text_applying_binary_resources">Application des ressources binaires</string>
|
||||
<string name="text_copying_native_libraries">Copie des bibliotheques natives</string>
|
||||
<string name="text_updating_project_config">Mise a jour de la config du projet</string>
|
||||
<string name="text_sign_stage_completed">Etape de signature terminee</string>
|
||||
<string name="text_writing_project_config">Ecriture de la config du projet</string>
|
||||
<string name="text_building_resources">Compilation des ressources</string>
|
||||
<string name="text_build_completed">Build termine</string>
|
||||
<string name="text_writing_resources_arsc">Ecriture de resources.arsc</string>
|
||||
<string name="text_writing_manifest">Ecriture du manifest</string>
|
||||
<string name="text_writing_app_icon">Ecriture de l\'icone de l\'appli</string>
|
||||
<string name="text_copying_asset">Copie d\'asset</string>
|
||||
<string name="text_preparing_assets_dir">Preparation du dir des assets</string>
|
||||
<string name="text_copying_library">Copie de bibliotheque</string>
|
||||
<string name="text_preparing_keystore">Preparation du keystore</string>
|
||||
<string name="text_unsigned_apk_created">APK non signe cree</string>
|
||||
<string name="text_creating_unsigned_apk">Creation de l\'APK non signe</string>
|
||||
<string name="text_using_keystore">Utilisation du keystore</string>
|
||||
<string name="text_re_signing_apk">Re-signature de l\'APK</string>
|
||||
<string name="text_writing_signed_apk">Ecriture de l\'APK signe</string>
|
||||
<string name="text_sign_completed">Signature terminee</string>
|
||||
<string name="text_clean_completed">Nettoyage termine</string>
|
||||
<string name="text_cleaning_workspace">Nettoyage de l\'espace de travail</string>
|
||||
<string name="text_resolving_plugin_native_libraries">Resolution des bibliotheques natives du plugin</string>
|
||||
<string name="text_copying_libraries_for_abi">Copie des bibliotheques pour ABI</string>
|
||||
<string name="text_selected_plugin">Plugin selectionne</string>
|
||||
<string name="text_extracted_plugin_libraries">Bibliotheques du plugin extraites</string>
|
||||
<string name="text_extracted_plugin_assets">Assets du plugin extraits</string>
|
||||
<string name="text_extracting_plugin_asset">Extraction d\'asset du plugin</string>
|
||||
<string name="text_extracting_plugin_so">Extraction du fichier so du plugin</string>
|
||||
</resources>
|
||||
@@ -8,11 +8,11 @@
|
||||
<!-- Proofreader: [ Google Gemini ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">建築...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">洗浄...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">パッケージング...</string>
|
||||
<string name="apk_builder_build">建築</string>
|
||||
<string name="apk_builder_clean">洗浄</string>
|
||||
<string name="apk_builder_package">パッケージング</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">apk builder の非互換バージョン.\n今すぐダウンロードしますか?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">準備中...</string>
|
||||
<string name="apk_builder_prepare">準備中</string>
|
||||
<string name="apk_info_device_sdk">デバイス SDK</string>
|
||||
<string name="apk_info_file_size">ファイルサイズ</string>
|
||||
<string name="apk_info_installed_version">インストール済み</string>
|
||||
@@ -535,7 +535,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">文書</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 ログ</string>
|
||||
<string name="text_app_shortcut_log_short_label">ログ</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 プラグインセンター</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 プラグイン</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">プラグイン</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 設定</string>
|
||||
<string name="text_app_shortcut_settings_short_label">設定</string>
|
||||
@@ -673,7 +673,7 @@
|
||||
<string name="text_delete_folder">フォルダーを削除</string>
|
||||
<string name="text_delete_line">行削除</string>
|
||||
<string name="text_delete_revision_confirm">この履歴を完全に削除しますか?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">削除中...</string>
|
||||
<string name="text_deleting">削除中</string>
|
||||
<string name="text_description">説明</string>
|
||||
<string name="text_deselect_all">全て解除</string>
|
||||
<string name="text_destination">宛先</string>
|
||||
@@ -1357,4 +1357,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">プラグイン \"%1$s\" はプラグインセンターで許可されていません</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">インストール済みアプリにプラグイン \"%1$s\" が見つかりません</string>
|
||||
<string name="error_unsupported_plugin_connection">サポートされていないプラグイン接続方式です</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">タイトル</string>
|
||||
<string name="text_content">内容</string>
|
||||
<string name="text_building_apk">APK をビルド中</string>
|
||||
<string name="text_built_apk_file_path">生成された APK のパス</string>
|
||||
<string name="text_clean">クリーン</string>
|
||||
<string name="text_sign">署名</string>
|
||||
<string name="text_build">ビルド</string>
|
||||
<string name="text_prepare">準備</string>
|
||||
<string name="text_preparing_workspace">ワークスペースを準備中</string>
|
||||
<string name="text_extracting_template_apk">テンプレート APK を展開中</string>
|
||||
<string name="text_prepare_completed">準備完了</string>
|
||||
<string name="text_copying_project_directory">プロジェクトディレクトリをコピー中</string>
|
||||
<string name="text_copying_script_file">スクリプトファイルをコピー中</string>
|
||||
<string name="text_source_processing_completed">ソース処理完了</string>
|
||||
<string name="text_copying_directory">ディレクトリをコピー中</string>
|
||||
<string name="text_copying_file">ファイルをコピー中</string>
|
||||
<string name="text_encrypting_script">スクリプトを暗号化中</string>
|
||||
<string name="text_replacing_file">ファイルを置換中</string>
|
||||
<string name="text_preparing_build_config">ビルド設定を準備中</string>
|
||||
<string name="text_reading_splash_resources">スプラッシュ資源を読み込み中</string>
|
||||
<string name="text_configuring_manifest">manifest を設定中</string>
|
||||
<string name="text_configuring_package_name">パッケージ名を設定中</string>
|
||||
<string name="text_copying_assets_to">assets をコピー中:</string>
|
||||
<string name="text_processing_source">ソースを処理中</string>
|
||||
<string name="text_applying_binary_resources">バイナリ資源を適用中</string>
|
||||
<string name="text_copying_native_libraries">ネイティブライブラリをコピー中</string>
|
||||
<string name="text_updating_project_config">プロジェクト設定を更新中</string>
|
||||
<string name="text_sign_stage_completed">署名ステージ完了</string>
|
||||
<string name="text_writing_project_config">プロジェクト設定を書き込み中</string>
|
||||
<string name="text_building_resources">資源をビルド中</string>
|
||||
<string name="text_build_completed">ビルド完了</string>
|
||||
<string name="text_writing_resources_arsc">resources.arsc を書き込み中</string>
|
||||
<string name="text_writing_manifest">manifest を書き込み中</string>
|
||||
<string name="text_writing_app_icon">アプリアイコンを書き込み中</string>
|
||||
<string name="text_copying_asset">asset をコピー中</string>
|
||||
<string name="text_preparing_assets_dir">assets ディレクトリを準備中</string>
|
||||
<string name="text_copying_library">ライブラリをコピー中</string>
|
||||
<string name="text_preparing_keystore">keystore を準備中</string>
|
||||
<string name="text_unsigned_apk_created">未署名 APK を作成しました</string>
|
||||
<string name="text_creating_unsigned_apk">未署名 APK を作成中</string>
|
||||
<string name="text_using_keystore">keystore を使用中</string>
|
||||
<string name="text_re_signing_apk">APK を再署名中</string>
|
||||
<string name="text_writing_signed_apk">署名済み APK を書き込み中</string>
|
||||
<string name="text_sign_completed">署名完了</string>
|
||||
<string name="text_clean_completed">クリーン完了</string>
|
||||
<string name="text_cleaning_workspace">ワークスペースをクリーン中</string>
|
||||
<string name="text_resolving_plugin_native_libraries">プラグインのネイティブライブラリを解決中</string>
|
||||
<string name="text_copying_libraries_for_abi">ABI 用ライブラリをコピー中</string>
|
||||
<string name="text_selected_plugin">選択したプラグイン</string>
|
||||
<string name="text_extracted_plugin_libraries">プラグインのライブラリを抽出しました</string>
|
||||
<string name="text_extracted_plugin_assets">プラグインの資源を抽出しました</string>
|
||||
<string name="text_extracting_plugin_asset">プラグイン資源を抽出中</string>
|
||||
<string name="text_extracting_plugin_so">プラグインの so を抽出中</string>
|
||||
</resources>
|
||||
@@ -9,11 +9,11 @@
|
||||
<!-- Proofreader: [ Google Gemini ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">건물...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">청소...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">포장...</string>
|
||||
<string name="apk_builder_build">건물</string>
|
||||
<string name="apk_builder_clean">청소</string>
|
||||
<string name="apk_builder_package">포장</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">\"APK Builder\" 의 호환되지 않는 버전.\n지금 다운로드 하시겠습니까?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">준비...</string>
|
||||
<string name="apk_builder_prepare">준비</string>
|
||||
<string name="apk_info_device_sdk">디바이스 SDK</string>
|
||||
<string name="apk_info_file_size">파일 크기</string>
|
||||
<string name="apk_info_installed_version">설치됨</string>
|
||||
@@ -536,7 +536,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">문서</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 통나무</string>
|
||||
<string name="text_app_shortcut_log_short_label">통나무</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 플러그인 센터</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 플러그인</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">플러그인</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 설정</string>
|
||||
<string name="text_app_shortcut_settings_short_label">설정</string>
|
||||
@@ -674,7 +674,7 @@
|
||||
<string name="text_delete_folder">폴더 삭제</string>
|
||||
<string name="text_delete_line">라인 삭제</string>
|
||||
<string name="text_delete_revision_confirm">이 버전을 영구 삭제할까요?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">삭제 중...</string>
|
||||
<string name="text_deleting">삭제 중</string>
|
||||
<string name="text_description">설명</string>
|
||||
<string name="text_deselect_all">전체 해제</string>
|
||||
<string name="text_destination">대상</string>
|
||||
@@ -1086,7 +1086,7 @@
|
||||
<string name="text_press_back_or_vol_down_to_close_window">창을 닫으려면 \"뒤로\" 또는 \"볼륨 감소\" 버튼을 누르세요</string>
|
||||
<string name="text_preview">시사</string>
|
||||
<string name="text_process_log">프로세스 로그</string>
|
||||
<string name="text_processing">처리</string>
|
||||
<string name="text_processing">처리 중</string>
|
||||
<string name="text_project">프로젝트</string>
|
||||
<string name="text_project_location">프로젝트 위치</string>
|
||||
<string name="text_project_media_access">프로젝트 미디어 액세스</string>
|
||||
@@ -1358,4 +1358,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">플러그인 \"%1$s\" 이 (가) 플러그인 센터에서 권한이 부여되지 않았습니다</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">설치된 앱에서 플러그인 \"%1$s\" 을 (를) 찾을 수 없습니다</string>
|
||||
<string name="error_unsupported_plugin_connection">지원되지 않는 플러그인 연결 방식입니다</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">제목</string>
|
||||
<string name="text_content">내용</string>
|
||||
<string name="text_building_apk">APK 빌드 중</string>
|
||||
<string name="text_built_apk_file_path">생성된 APK 경로</string>
|
||||
<string name="text_clean">정리</string>
|
||||
<string name="text_sign">서명</string>
|
||||
<string name="text_build">빌드</string>
|
||||
<string name="text_prepare">준비</string>
|
||||
<string name="text_preparing_workspace">작업 공간 준비 중</string>
|
||||
<string name="text_extracting_template_apk">템플릿 APK 추출 중</string>
|
||||
<string name="text_prepare_completed">준비 완료</string>
|
||||
<string name="text_copying_project_directory">프로젝트 디렉터리 복사 중</string>
|
||||
<string name="text_copying_script_file">스크립트 파일 복사 중</string>
|
||||
<string name="text_source_processing_completed">소스 처리 완료</string>
|
||||
<string name="text_copying_directory">디렉터리 복사 중</string>
|
||||
<string name="text_copying_file">파일 복사 중</string>
|
||||
<string name="text_encrypting_script">스크립트 암호화 중</string>
|
||||
<string name="text_replacing_file">파일 교체 중</string>
|
||||
<string name="text_preparing_build_config">빌드 설정 준비 중</string>
|
||||
<string name="text_reading_splash_resources">스플래시 리소스 읽는 중</string>
|
||||
<string name="text_configuring_manifest">manifest 설정 중</string>
|
||||
<string name="text_configuring_package_name">패키지 이름 설정 중</string>
|
||||
<string name="text_copying_assets_to">assets 복사 중:</string>
|
||||
<string name="text_processing_source">소스 처리 중</string>
|
||||
<string name="text_applying_binary_resources">바이너리 리소스 적용 중</string>
|
||||
<string name="text_copying_native_libraries">네이티브 라이브러리 복사 중</string>
|
||||
<string name="text_updating_project_config">프로젝트 설정 업데이트 중</string>
|
||||
<string name="text_sign_stage_completed">서명 단계 완료</string>
|
||||
<string name="text_writing_project_config">프로젝트 설정 기록 중</string>
|
||||
<string name="text_building_resources">리소스 빌드 중</string>
|
||||
<string name="text_build_completed">빌드 완료</string>
|
||||
<string name="text_writing_resources_arsc">resources.arsc 기록 중</string>
|
||||
<string name="text_writing_manifest">manifest 기록 중</string>
|
||||
<string name="text_writing_app_icon">앱 아이콘 기록 중</string>
|
||||
<string name="text_copying_asset">asset 복사 중</string>
|
||||
<string name="text_preparing_assets_dir">assets 디렉터리 준비 중</string>
|
||||
<string name="text_copying_library">라이브러리 복사 중</string>
|
||||
<string name="text_preparing_keystore">keystore 준비 중</string>
|
||||
<string name="text_unsigned_apk_created">서명되지 않은 APK가 생성됨</string>
|
||||
<string name="text_creating_unsigned_apk">서명되지 않은 APK 생성 중</string>
|
||||
<string name="text_using_keystore">keystore 사용 중</string>
|
||||
<string name="text_re_signing_apk">APK 재서명 중</string>
|
||||
<string name="text_writing_signed_apk">서명된 APK 기록 중</string>
|
||||
<string name="text_sign_completed">서명 완료</string>
|
||||
<string name="text_clean_completed">정리 완료</string>
|
||||
<string name="text_cleaning_workspace">작업 공간 정리 중</string>
|
||||
<string name="text_resolving_plugin_native_libraries">플러그인 네이티브 라이브러리 확인 중</string>
|
||||
<string name="text_copying_libraries_for_abi">ABI용 라이브러리 복사 중</string>
|
||||
<string name="text_selected_plugin">선택된 플러그인</string>
|
||||
<string name="text_extracted_plugin_libraries">플러그인 라이브러리를 추출함</string>
|
||||
<string name="text_extracted_plugin_assets">플러그인 assets를 추출함</string>
|
||||
<string name="text_extracting_plugin_asset">플러그인 asset 추출 중</string>
|
||||
<string name="text_extracting_plugin_so">플러그인 so 파일 추출 중</string>
|
||||
</resources>
|
||||
@@ -7,11 +7,11 @@
|
||||
<!-- Proofreader: [ JetBrains AI Assistant ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">Строительство...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">Очистка...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">Упаковка...</string>
|
||||
<string name="apk_builder_build">Строительство</string>
|
||||
<string name="apk_builder_clean">Очистка</string>
|
||||
<string name="apk_builder_package">Упаковка</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">Несовместимая версия \"apk builder\".\nЗагрузить ее сейчас?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">Подготовка...</string>
|
||||
<string name="apk_builder_prepare">Подготовка</string>
|
||||
<string name="apk_info_device_sdk">SDK устройства</string>
|
||||
<string name="apk_info_file_size">Размер файла</string>
|
||||
<string name="apk_info_installed_version">Установлено</string>
|
||||
@@ -534,7 +534,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">документы</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 Журнал</string>
|
||||
<string name="text_app_shortcut_log_short_label">Журнал</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">Центр плагинов AutoJs6</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Плагины</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">Плагины</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 Настройки</string>
|
||||
<string name="text_app_shortcut_settings_short_label">Настройки</string>
|
||||
@@ -672,7 +672,7 @@
|
||||
<string name="text_delete_folder">Удалить папку</string>
|
||||
<string name="text_delete_line">Удалить строку</string>
|
||||
<string name="text_delete_revision_confirm">Удалить эту ревизию навсегда?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">Удаление...</string>
|
||||
<string name="text_deleting">Удаление</string>
|
||||
<string name="text_description">Описание</string>
|
||||
<string name="text_deselect_all">Снять выделение</string>
|
||||
<string name="text_destination">Назначение</string>
|
||||
@@ -1356,4 +1356,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">Плагин \"%1$s\" не авторизован в Центре плагинов</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">Плагин \"%1$s\" не найден среди установленных приложений</string>
|
||||
<string name="error_unsupported_plugin_connection">Неподдерживаемое подключение плагина</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">Заголовок</string>
|
||||
<string name="text_content">Содержимое</string>
|
||||
<string name="text_building_apk">Сборка APK</string>
|
||||
<string name="text_built_apk_file_path">Путь к собранному APK</string>
|
||||
<string name="text_clean">Очистить</string>
|
||||
<string name="text_sign">Подписать</string>
|
||||
<string name="text_build">Собрать</string>
|
||||
<string name="text_prepare">Подготовить</string>
|
||||
<string name="text_preparing_workspace">Подготовка рабочей области</string>
|
||||
<string name="text_extracting_template_apk">Извлечение шаблонного APK</string>
|
||||
<string name="text_prepare_completed">Подготовка завершена</string>
|
||||
<string name="text_copying_project_directory">Копирование каталога проекта</string>
|
||||
<string name="text_copying_script_file">Копирование файла скрипта</string>
|
||||
<string name="text_source_processing_completed">Обработка исходников завершена</string>
|
||||
<string name="text_copying_directory">Копирование каталога</string>
|
||||
<string name="text_copying_file">Копирование файла</string>
|
||||
<string name="text_encrypting_script">Шифрование скрипта</string>
|
||||
<string name="text_replacing_file">Замена файла</string>
|
||||
<string name="text_preparing_build_config">Подготовка конфигурации сборки</string>
|
||||
<string name="text_reading_splash_resources">Чтение ресурсов заставки</string>
|
||||
<string name="text_configuring_manifest">Настройка manifest</string>
|
||||
<string name="text_configuring_package_name">Настройка имени пакета</string>
|
||||
<string name="text_copying_assets_to">Копирование assets в</string>
|
||||
<string name="text_processing_source">Обработка исходников</string>
|
||||
<string name="text_applying_binary_resources">Применение бинарных ресурсов</string>
|
||||
<string name="text_copying_native_libraries">Копирование нативных библиотек</string>
|
||||
<string name="text_updating_project_config">Обновление конфигурации проекта</string>
|
||||
<string name="text_sign_stage_completed">Этап подписи завершен</string>
|
||||
<string name="text_writing_project_config">Запись конфигурации проекта</string>
|
||||
<string name="text_building_resources">Сборка ресурсов</string>
|
||||
<string name="text_build_completed">Сборка завершена</string>
|
||||
<string name="text_writing_resources_arsc">Запись resources.arsc</string>
|
||||
<string name="text_writing_manifest">Запись manifest</string>
|
||||
<string name="text_writing_app_icon">Запись значка приложения</string>
|
||||
<string name="text_copying_asset">Копирование asset</string>
|
||||
<string name="text_preparing_assets_dir">Подготовка каталога assets</string>
|
||||
<string name="text_copying_library">Копирование библиотеки</string>
|
||||
<string name="text_preparing_keystore">Подготовка keystore</string>
|
||||
<string name="text_unsigned_apk_created">Неподписанный APK создан</string>
|
||||
<string name="text_creating_unsigned_apk">Создание неподписанного APK</string>
|
||||
<string name="text_using_keystore">Использование keystore</string>
|
||||
<string name="text_re_signing_apk">Повторная подпись APK</string>
|
||||
<string name="text_writing_signed_apk">Запись подписанного APK</string>
|
||||
<string name="text_sign_completed">Подпись завершена</string>
|
||||
<string name="text_clean_completed">Очистка завершена</string>
|
||||
<string name="text_cleaning_workspace">Очистка рабочей области</string>
|
||||
<string name="text_resolving_plugin_native_libraries">Разбор нативных библиотек плагина</string>
|
||||
<string name="text_copying_libraries_for_abi">Копирование библиотек для ABI</string>
|
||||
<string name="text_selected_plugin">Выбранный плагин</string>
|
||||
<string name="text_extracted_plugin_libraries">Библиотеки плагина извлечены</string>
|
||||
<string name="text_extracted_plugin_assets">Assets плагина извлечены</string>
|
||||
<string name="text_extracting_plugin_asset">Извлечение asset плагина</string>
|
||||
<string name="text_extracting_plugin_so">Извлечение файла so плагина</string>
|
||||
</resources>
|
||||
@@ -4,11 +4,11 @@
|
||||
<!-- Proofreader: [ SuperMonster003 ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">構建中...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">清理臨時文件...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">打包中...</string>
|
||||
<string name="apk_builder_build">構建中</string>
|
||||
<string name="apk_builder_clean">清理臨時文件</string>
|
||||
<string name="apk_builder_package">打包中</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">打包插件需更新\n是否下載</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">準備文件...</string>
|
||||
<string name="apk_builder_prepare">準備文件</string>
|
||||
<string name="apk_info_device_sdk">設備 SDK</string>
|
||||
<string name="apk_info_file_size">文件大小</string>
|
||||
<string name="apk_info_installed_version">已安裝</string>
|
||||
@@ -530,7 +530,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">文檔</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 日誌</string>
|
||||
<string name="text_app_shortcut_log_short_label">日誌</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 插件中心</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 插件</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">插件</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 設置</string>
|
||||
<string name="text_app_shortcut_settings_short_label">設置</string>
|
||||
@@ -668,7 +668,7 @@
|
||||
<string name="text_delete_folder">刪除文件夾</string>
|
||||
<string name="text_delete_line">刪除行</string>
|
||||
<string name="text_delete_revision_confirm">是否永久刪除此版本記錄</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">正在刪除...</string>
|
||||
<string name="text_deleting">正在刪除</string>
|
||||
<string name="text_description">描述</string>
|
||||
<string name="text_deselect_all">取消全選</string>
|
||||
<string name="text_destination">目標</string>
|
||||
@@ -1080,7 +1080,7 @@
|
||||
<string name="text_press_back_or_vol_down_to_close_window">如需關閉窗口, 可按 \"返回鍵\" 或 \"音量減鍵\"</string>
|
||||
<string name="text_preview">預覽</string>
|
||||
<string name="text_process_log">流程日誌</string>
|
||||
<string name="text_processing">處理中</string>
|
||||
<string name="text_processing">正在處理</string>
|
||||
<string name="text_project">項目</string>
|
||||
<string name="text_project_location">項目位置</string>
|
||||
<string name="text_project_media_access">投影媒體權限</string>
|
||||
@@ -1352,4 +1352,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">插件 \"%1$s\" 未在插件中心獲得授權</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">已安裝應用中未找到插件 \"%1$s\"</string>
|
||||
<string name="error_unsupported_plugin_connection">不支持的插件連接方式</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">標題</string>
|
||||
<string name="text_content">內容</string>
|
||||
<string name="text_building_apk">正在打包應用</string>
|
||||
<string name="text_built_apk_file_path">打包應用文件路徑</string>
|
||||
<string name="text_clean">清理</string>
|
||||
<string name="text_sign">簽名</string>
|
||||
<string name="text_build">構建</string>
|
||||
<string name="text_prepare">準備</string>
|
||||
<string name="text_preparing_workspace">正在準備工作區</string>
|
||||
<string name="text_extracting_template_apk">正在提取模板 APK</string>
|
||||
<string name="text_prepare_completed">準備完成</string>
|
||||
<string name="text_copying_project_directory">正在複製項目目錄</string>
|
||||
<string name="text_copying_script_file">正在複製腳本文件</string>
|
||||
<string name="text_source_processing_completed">源代碼處理完成</string>
|
||||
<string name="text_copying_directory">正在複製目錄</string>
|
||||
<string name="text_copying_file">正在複製文件</string>
|
||||
<string name="text_encrypting_script">正在加密腳本</string>
|
||||
<string name="text_replacing_file">正在替換文件</string>
|
||||
<string name="text_preparing_build_config">正在準備構建配置</string>
|
||||
<string name="text_reading_splash_resources">正在讀取啓動頁資源</string>
|
||||
<string name="text_configuring_manifest">正在配置清單文件</string>
|
||||
<string name="text_configuring_package_name">正在配置包名</string>
|
||||
<string name="text_copying_assets_to">正在複製資源到</string>
|
||||
<string name="text_processing_source">正在處理源代碼</string>
|
||||
<string name="text_applying_binary_resources">正在應用二進制資源</string>
|
||||
<string name="text_copying_native_libraries">正在複製原生庫</string>
|
||||
<string name="text_updating_project_config">正在更新項目配置</string>
|
||||
<string name="text_sign_stage_completed">簽名階段完成</string>
|
||||
<string name="text_writing_project_config">正在寫入項目配置</string>
|
||||
<string name="text_building_resources">正在構建資源</string>
|
||||
<string name="text_build_completed">構建完成</string>
|
||||
<string name="text_writing_resources_arsc">正在寫入 resources.arsc</string>
|
||||
<string name="text_writing_manifest">正在寫入清單文件</string>
|
||||
<string name="text_writing_app_icon">正在寫入應用圖標</string>
|
||||
<string name="text_copying_asset">正在複製資源</string>
|
||||
<string name="text_preparing_assets_dir">正在準備資源目錄</string>
|
||||
<string name="text_copying_library">正在複製庫文件</string>
|
||||
<string name="text_preparing_keystore">正在準備密鑰庫</string>
|
||||
<string name="text_unsigned_apk_created">未簽名 APK 已創建</string>
|
||||
<string name="text_creating_unsigned_apk">正在創建未簽名 APK</string>
|
||||
<string name="text_using_keystore">正在使用密鑰庫</string>
|
||||
<string name="text_re_signing_apk">正在重新簽名 APK</string>
|
||||
<string name="text_writing_signed_apk">正在寫入已簽名 APK</string>
|
||||
<string name="text_sign_completed">簽名完成</string>
|
||||
<string name="text_clean_completed">清理完成</string>
|
||||
<string name="text_cleaning_workspace">正在清理工作區</string>
|
||||
<string name="text_resolving_plugin_native_libraries">正在解析插件原生庫</string>
|
||||
<string name="text_copying_libraries_for_abi">正在複製 ABI 庫文件</string>
|
||||
<string name="text_selected_plugin">已選擇插件</string>
|
||||
<string name="text_extracted_plugin_libraries">已提取插件庫文件</string>
|
||||
<string name="text_extracted_plugin_assets">已提取插件資源</string>
|
||||
<string name="text_extracting_plugin_asset">正在提取插件資源</string>
|
||||
<string name="text_extracting_plugin_so">正在提取插件 so 文件</string>
|
||||
</resources>
|
||||
@@ -4,11 +4,11 @@
|
||||
<!-- Proofreader: [ SuperMonster003 ] -->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">構建中...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">清理臨時檔案...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">打包中...</string>
|
||||
<string name="apk_builder_build">構建中</string>
|
||||
<string name="apk_builder_clean">清理臨時檔案</string>
|
||||
<string name="apk_builder_package">打包中</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">打包外掛需更新\n是否下載</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">準備檔案...</string>
|
||||
<string name="apk_builder_prepare">準備檔案</string>
|
||||
<string name="apk_info_device_sdk">裝置 SDK</string>
|
||||
<string name="apk_info_file_size">檔案大小</string>
|
||||
<string name="apk_info_installed_version">已安裝</string>
|
||||
@@ -530,7 +530,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">文件</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 日誌</string>
|
||||
<string name="text_app_shortcut_log_short_label">日誌</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 外掛中心</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 外掛</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">外掛</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 設定</string>
|
||||
<string name="text_app_shortcut_settings_short_label">設定</string>
|
||||
@@ -668,7 +668,7 @@
|
||||
<string name="text_delete_folder">刪除資料夾</string>
|
||||
<string name="text_delete_line">刪除行</string>
|
||||
<string name="text_delete_revision_confirm">是否永久刪除此版本記錄</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">正在刪除...</string>
|
||||
<string name="text_deleting">正在刪除</string>
|
||||
<string name="text_description">描述</string>
|
||||
<string name="text_deselect_all">取消全選</string>
|
||||
<string name="text_destination">目標</string>
|
||||
@@ -1080,7 +1080,7 @@
|
||||
<string name="text_press_back_or_vol_down_to_close_window">如需關閉視窗, 可按 \"返回鍵\" 或 \"音量減鍵\"</string>
|
||||
<string name="text_preview">預覽</string>
|
||||
<string name="text_process_log">流程日誌</string>
|
||||
<string name="text_processing">處理中</string>
|
||||
<string name="text_processing">正在處理</string>
|
||||
<string name="text_project">專案</string>
|
||||
<string name="text_project_location">專案位置</string>
|
||||
<string name="text_project_media_access">投影媒體許可權</string>
|
||||
@@ -1352,4 +1352,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">外掛 \"%1$s\" 未在外掛中心獲得授權</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">已安裝應用中未找到外掛 \"%1$s\"</string>
|
||||
<string name="error_unsupported_plugin_connection">不支援的外掛連線方式</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">標題</string>
|
||||
<string name="text_content">內容</string>
|
||||
<string name="text_building_apk">正在打包應用</string>
|
||||
<string name="text_built_apk_file_path">打包應用檔案路徑</string>
|
||||
<string name="text_clean">清理</string>
|
||||
<string name="text_sign">簽名</string>
|
||||
<string name="text_build">構建</string>
|
||||
<string name="text_prepare">準備</string>
|
||||
<string name="text_preparing_workspace">正在準備工作區</string>
|
||||
<string name="text_extracting_template_apk">正在提取模板 APK</string>
|
||||
<string name="text_prepare_completed">準備完成</string>
|
||||
<string name="text_copying_project_directory">正在複製專案目錄</string>
|
||||
<string name="text_copying_script_file">正在複製指令碼檔案</string>
|
||||
<string name="text_source_processing_completed">原始碼處理完成</string>
|
||||
<string name="text_copying_directory">正在複製目錄</string>
|
||||
<string name="text_copying_file">正在複製檔案</string>
|
||||
<string name="text_encrypting_script">正在加密指令碼</string>
|
||||
<string name="text_replacing_file">正在替換檔案</string>
|
||||
<string name="text_preparing_build_config">正在準備構建配置</string>
|
||||
<string name="text_reading_splash_resources">正在讀取啟動頁資源</string>
|
||||
<string name="text_configuring_manifest">正在配置清單檔案</string>
|
||||
<string name="text_configuring_package_name">正在配置包名</string>
|
||||
<string name="text_copying_assets_to">正在複製資源到</string>
|
||||
<string name="text_processing_source">正在處理原始碼</string>
|
||||
<string name="text_applying_binary_resources">正在應用二進位制資源</string>
|
||||
<string name="text_copying_native_libraries">正在複製原生庫</string>
|
||||
<string name="text_updating_project_config">正在更新專案配置</string>
|
||||
<string name="text_sign_stage_completed">簽名階段完成</string>
|
||||
<string name="text_writing_project_config">正在寫入專案配置</string>
|
||||
<string name="text_building_resources">正在構建資源</string>
|
||||
<string name="text_build_completed">構建完成</string>
|
||||
<string name="text_writing_resources_arsc">正在寫入 resources.arsc</string>
|
||||
<string name="text_writing_manifest">正在寫入清單檔案</string>
|
||||
<string name="text_writing_app_icon">正在寫入應用圖示</string>
|
||||
<string name="text_copying_asset">正在複製資源</string>
|
||||
<string name="text_preparing_assets_dir">正在準備資源目錄</string>
|
||||
<string name="text_copying_library">正在複製庫檔案</string>
|
||||
<string name="text_preparing_keystore">正在準備金鑰庫</string>
|
||||
<string name="text_unsigned_apk_created">未簽名 APK 已建立</string>
|
||||
<string name="text_creating_unsigned_apk">正在建立未簽名 APK</string>
|
||||
<string name="text_using_keystore">正在使用金鑰庫</string>
|
||||
<string name="text_re_signing_apk">正在重新簽名 APK</string>
|
||||
<string name="text_writing_signed_apk">正在寫入已簽名 APK</string>
|
||||
<string name="text_sign_completed">簽名完成</string>
|
||||
<string name="text_clean_completed">清理完成</string>
|
||||
<string name="text_cleaning_workspace">正在清理工作區</string>
|
||||
<string name="text_resolving_plugin_native_libraries">正在解析外掛原生庫</string>
|
||||
<string name="text_copying_libraries_for_abi">正在複製 ABI 庫檔案</string>
|
||||
<string name="text_selected_plugin">已選擇外掛</string>
|
||||
<string name="text_extracted_plugin_libraries">已提取外掛庫檔案</string>
|
||||
<string name="text_extracted_plugin_assets">已提取外掛資源</string>
|
||||
<string name="text_extracting_plugin_asset">正在提取外掛資源</string>
|
||||
<string name="text_extracting_plugin_so">正在提取外掛 so 檔案</string>
|
||||
</resources>
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">构建中...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">清理临时文件...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">打包中...</string>
|
||||
<string name="apk_builder_build">构建中</string>
|
||||
<string name="apk_builder_clean">清理临时文件</string>
|
||||
<string name="apk_builder_package">打包中</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">打包插件需更新\n是否下载</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">准备文件...</string>
|
||||
<string name="apk_builder_prepare">准备文件</string>
|
||||
<string name="apk_info_device_sdk">设备 SDK</string>
|
||||
<string name="apk_info_file_size">文件大小</string>
|
||||
<string name="apk_info_installed_version">已安装</string>
|
||||
@@ -531,7 +531,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">文档</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 日志</string>
|
||||
<string name="text_app_shortcut_log_short_label">日志</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 插件中心</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 插件</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">插件</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 设置</string>
|
||||
<string name="text_app_shortcut_settings_short_label">设置</string>
|
||||
@@ -669,7 +669,7 @@
|
||||
<string name="text_delete_folder">删除文件夹</string>
|
||||
<string name="text_delete_line">删除行</string>
|
||||
<string name="text_delete_revision_confirm">是否永久删除此版本记录</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">正在删除...</string>
|
||||
<string name="text_deleting">正在删除</string>
|
||||
<string name="text_description">描述</string>
|
||||
<string name="text_deselect_all">取消全选</string>
|
||||
<string name="text_destination">目标</string>
|
||||
@@ -1081,7 +1081,7 @@
|
||||
<string name="text_press_back_or_vol_down_to_close_window">如需关闭窗口, 可按 \"返回键\" 或 \"音量减键\"</string>
|
||||
<string name="text_preview">预览</string>
|
||||
<string name="text_process_log">流程日志</string>
|
||||
<string name="text_processing">处理中</string>
|
||||
<string name="text_processing">正在处理</string>
|
||||
<string name="text_project">项目</string>
|
||||
<string name="text_project_location">项目位置</string>
|
||||
<string name="text_project_media_access">投影媒体权限</string>
|
||||
@@ -1353,4 +1353,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">插件 \"%1$s\" 未在插件中心获得授权</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">已安装应用中未找到插件 \"%1$s\"</string>
|
||||
<string name="error_unsupported_plugin_connection">不支持的插件连接方式</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">标题</string>
|
||||
<string name="text_content">内容</string>
|
||||
<string name="text_building_apk">正在打包应用</string>
|
||||
<string name="text_built_apk_file_path">打包应用文件路径</string>
|
||||
<string name="text_clean">清理</string>
|
||||
<string name="text_sign">签名</string>
|
||||
<string name="text_build">构建</string>
|
||||
<string name="text_prepare">准备</string>
|
||||
<string name="text_preparing_workspace">正在准备工作区</string>
|
||||
<string name="text_extracting_template_apk">正在提取模板 APK</string>
|
||||
<string name="text_prepare_completed">准备完成</string>
|
||||
<string name="text_copying_project_directory">正在复制项目目录</string>
|
||||
<string name="text_copying_script_file">正在复制脚本文件</string>
|
||||
<string name="text_source_processing_completed">源代码处理完成</string>
|
||||
<string name="text_copying_directory">正在复制目录</string>
|
||||
<string name="text_copying_file">正在复制文件</string>
|
||||
<string name="text_encrypting_script">正在加密脚本</string>
|
||||
<string name="text_replacing_file">正在替换文件</string>
|
||||
<string name="text_preparing_build_config">正在准备构建配置</string>
|
||||
<string name="text_reading_splash_resources">正在读取启动页资源</string>
|
||||
<string name="text_configuring_manifest">正在配置清单文件</string>
|
||||
<string name="text_configuring_package_name">正在配置包名</string>
|
||||
<string name="text_copying_assets_to">正在复制资源到</string>
|
||||
<string name="text_processing_source">正在处理源代码</string>
|
||||
<string name="text_applying_binary_resources">正在应用二进制资源</string>
|
||||
<string name="text_copying_native_libraries">正在复制原生库</string>
|
||||
<string name="text_updating_project_config">正在更新项目配置</string>
|
||||
<string name="text_sign_stage_completed">签名阶段完成</string>
|
||||
<string name="text_writing_project_config">正在写入项目配置</string>
|
||||
<string name="text_building_resources">正在构建资源</string>
|
||||
<string name="text_build_completed">构建完成</string>
|
||||
<string name="text_writing_resources_arsc">正在写入 resources.arsc</string>
|
||||
<string name="text_writing_manifest">正在写入清单文件</string>
|
||||
<string name="text_writing_app_icon">正在写入应用图标</string>
|
||||
<string name="text_copying_asset">正在复制资源</string>
|
||||
<string name="text_preparing_assets_dir">正在准备资源目录</string>
|
||||
<string name="text_copying_library">正在复制库文件</string>
|
||||
<string name="text_preparing_keystore">正在准备密钥库</string>
|
||||
<string name="text_unsigned_apk_created">未签名 APK 已创建</string>
|
||||
<string name="text_creating_unsigned_apk">正在创建未签名 APK</string>
|
||||
<string name="text_using_keystore">正在使用密钥库</string>
|
||||
<string name="text_re_signing_apk">正在重新签名 APK</string>
|
||||
<string name="text_writing_signed_apk">正在写入已签名 APK</string>
|
||||
<string name="text_sign_completed">签名完成</string>
|
||||
<string name="text_clean_completed">清理完成</string>
|
||||
<string name="text_cleaning_workspace">正在清理工作区</string>
|
||||
<string name="text_resolving_plugin_native_libraries">正在解析插件原生库</string>
|
||||
<string name="text_copying_libraries_for_abi">正在复制 ABI 库文件</string>
|
||||
<string name="text_selected_plugin">已选择插件</string>
|
||||
<string name="text_extracted_plugin_libraries">已提取插件库文件</string>
|
||||
<string name="text_extracted_plugin_assets">已提取插件资源</string>
|
||||
<string name="text_extracting_plugin_asset">正在提取插件资源</string>
|
||||
<string name="text_extracting_plugin_so">正在提取插件 so 文件</string>
|
||||
</resources>
|
||||
@@ -69,5 +69,9 @@
|
||||
<dimen name="ref_md_listitem_textsize">16sp</dimen>
|
||||
<dimen name="ref_md_listitem_height">48dp</dimen>
|
||||
<dimen name="toolbar_menu_item_width">40dp</dimen>
|
||||
<dimen name="build_progress_icon_size">24dp</dimen>
|
||||
<dimen name="build_progress_icon_text_gap">12dp</dimen>
|
||||
<dimen name="build_progress_icon_text_size">16sp</dimen>
|
||||
<dimen name="build_progress_row_spacing">12dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -277,11 +277,11 @@
|
||||
<!-- Dividing line between translatable and non-translatable -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
|
||||
<string name="apk_builder_build" tools:ignore="TypographyEllipsis">Building...</string>
|
||||
<string name="apk_builder_clean" tools:ignore="TypographyEllipsis">Cleaning...</string>
|
||||
<string name="apk_builder_package" tools:ignore="TypographyEllipsis">Packaging...</string>
|
||||
<string name="apk_builder_build">Building</string>
|
||||
<string name="apk_builder_clean">Cleaning</string>
|
||||
<string name="apk_builder_package">Packaging</string>
|
||||
<string name="apk_builder_plugin_version_incompatible">Incompatible version of \"apk builder\".\nDownload it now?</string>
|
||||
<string name="apk_builder_prepare" tools:ignore="TypographyEllipsis">Preparing...</string>
|
||||
<string name="apk_builder_prepare">Preparing</string>
|
||||
<string name="apk_info_device_sdk">Device SDK</string>
|
||||
<string name="apk_info_file_size">File size</string>
|
||||
<string name="apk_info_installed_version">Installed</string>
|
||||
@@ -807,7 +807,7 @@
|
||||
<string name="text_app_shortcut_docs_short_label">Docs</string>
|
||||
<string name="text_app_shortcut_log_long_label">AutoJs6 Log</string>
|
||||
<string name="text_app_shortcut_log_short_label">Log</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugin Center</string>
|
||||
<string name="text_app_shortcut_plugin_center_long_label">AutoJs6 Plugins</string>
|
||||
<string name="text_app_shortcut_plugin_center_short_label">Plugins</string>
|
||||
<string name="text_app_shortcut_settings_long_label">AutoJs6 Settings</string>
|
||||
<string name="text_app_shortcut_settings_short_label">Settings</string>
|
||||
@@ -945,7 +945,7 @@
|
||||
<string name="text_delete_folder">Delete folder</string>
|
||||
<string name="text_delete_line">Delete line</string>
|
||||
<string name="text_delete_revision_confirm">Delete this revision permanently?</string>
|
||||
<string name="text_deleting" tools:ignore="TypographyEllipsis">Deleting...</string>
|
||||
<string name="text_deleting">Deleting</string>
|
||||
<string name="text_description">Description</string>
|
||||
<string name="text_deselect_all">Deselect all</string>
|
||||
<string name="text_destination">Destination</string>
|
||||
@@ -1048,7 +1048,7 @@
|
||||
<string name="text_file_name">File name</string>
|
||||
<string name="text_file_name_colon_value">File name: %1$s</string>
|
||||
<string name="text_file_not_exists">File does not exist</string>
|
||||
<string name="text_file_path">File Path</string>
|
||||
<string name="text_file_path">File path</string>
|
||||
<string name="text_file_with_abs_path_is_not_an_executable_script">File \"%1$s\" is not an executable script</string>
|
||||
<string name="text_filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="text_filename_cannot_contain_invalid_character">Filename cannot contain the following characters: \\ / : * ? " < > |</string>
|
||||
@@ -1629,4 +1629,58 @@
|
||||
<string name="error_plugin_is_not_authorized_in_plugin_center">Plugin \"%1$s\" is not authorized in Plugin Center</string>
|
||||
<string name="error_plugin_not_found_in_installed_apps">Plugin \"%1$s\" not found in installed apps</string>
|
||||
<string name="error_unsupported_plugin_connection">Unsupported plugin connection</string>
|
||||
<string name="text_property_colon">%1$s:</string>
|
||||
<string name="text_title">Title</string>
|
||||
<string name="text_content">Content</string>
|
||||
<string name="text_building_apk">Building APK</string>
|
||||
<string name="text_built_apk_file_path">Built APK file path</string>
|
||||
<string name="text_clean">Clean</string>
|
||||
<string name="text_sign">Sign</string>
|
||||
<string name="text_build">Build</string>
|
||||
<string name="text_prepare">Prepare</string>
|
||||
<string name="text_preparing_workspace">Preparing workspace</string>
|
||||
<string name="text_extracting_template_apk">Extracting template APK</string>
|
||||
<string name="text_prepare_completed">Prepare completed</string>
|
||||
<string name="text_copying_project_directory">Copying project directory</string>
|
||||
<string name="text_copying_script_file">Copying script file</string>
|
||||
<string name="text_source_processing_completed">Source processing completed</string>
|
||||
<string name="text_copying_directory">Copying directory</string>
|
||||
<string name="text_copying_file">Copying file</string>
|
||||
<string name="text_encrypting_script">Encrypting script</string>
|
||||
<string name="text_replacing_file">Replacing file</string>
|
||||
<string name="text_preparing_build_config">Preparing build config</string>
|
||||
<string name="text_reading_splash_resources">Reading splash resources</string>
|
||||
<string name="text_configuring_manifest">Configuring manifest</string>
|
||||
<string name="text_configuring_package_name">Configuring package name</string>
|
||||
<string name="text_copying_assets_to">Copying assets to</string>
|
||||
<string name="text_processing_source">Processing source</string>
|
||||
<string name="text_applying_binary_resources">Applying binary resources</string>
|
||||
<string name="text_copying_native_libraries">Copying native libraries</string>
|
||||
<string name="text_updating_project_config">Updating project config</string>
|
||||
<string name="text_sign_stage_completed">Sign stage completed</string>
|
||||
<string name="text_writing_project_config">Writing project config</string>
|
||||
<string name="text_building_resources">Building resources</string>
|
||||
<string name="text_build_completed">Build completed</string>
|
||||
<string name="text_writing_resources_arsc">Writing resources.arsc</string>
|
||||
<string name="text_writing_manifest">Writing manifest</string>
|
||||
<string name="text_writing_app_icon">Writing app icon</string>
|
||||
<string name="text_copying_asset">Copying asset</string>
|
||||
<string name="text_preparing_assets_dir">Preparing assets dir</string>
|
||||
<string name="text_copying_library">Copying library</string>
|
||||
<string name="text_preparing_keystore">Preparing keystore</string>
|
||||
<string name="text_unsigned_apk_created">Unsigned APK created</string>
|
||||
<string name="text_creating_unsigned_apk">Creating unsigned APK</string>
|
||||
<string name="text_using_keystore">Using keystore</string>
|
||||
<string name="text_re_signing_apk">Re-signing APK</string>
|
||||
<string name="text_writing_signed_apk">Writing signed APK</string>
|
||||
<string name="text_sign_completed">Sign completed</string>
|
||||
<string name="text_clean_completed">Clean completed</string>
|
||||
<string name="text_cleaning_workspace">Cleaning workspace</string>
|
||||
<string name="text_resolving_plugin_native_libraries">Resolving plugin native libraries</string>
|
||||
<string name="text_copying_libraries_for_abi">Copying libraries for ABI</string>
|
||||
<string name="text_selected_plugin">Selected plugin</string>
|
||||
<string name="text_extracted_plugin_libraries">Extracted plugin libraries</string>
|
||||
<string name="text_extracted_plugin_assets">Extracted plugin assets</string>
|
||||
<string name="text_extracting_plugin_asset">Extracting plugin asset</string>
|
||||
<string name="text_extracting_plugin_so">Extracting plugin so</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user