mirror of
https://github.com/RoboSats/robosats.git
synced 2025-08-14 09:17:14 +00:00
Update Android architecture versioning strategy
This commit is contained in:
4
.github/workflows/android-build.yml
vendored
4
.github/workflows/android-build.yml
vendored
@ -17,10 +17,10 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
push:
|
push:
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
paths: [ "mobile", "frontend" ]
|
paths: [ "android", "frontend" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
paths: [ "mobile", "frontend" ]
|
paths: [ "android", "frontend" ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-android:
|
build-android:
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import com.android.build.api.dsl.Packaging
|
import com.android.build.api.dsl.Packaging
|
||||||
|
|
||||||
|
val baseVersionCode = 81
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
@ -13,7 +15,7 @@ android {
|
|||||||
applicationId = "com.robosats"
|
applicationId = "com.robosats"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 15
|
versionCode = baseVersionCode
|
||||||
versionName = "0.8.1-alpha"
|
versionName = "0.8.1-alpha"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
@ -60,11 +62,30 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
packaging {
|
packaging {
|
||||||
jniLibs.useLegacyPackaging = true
|
jniLibs.useLegacyPackaging = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure unique version codes for ABI splits to prevent downgrade issues
|
||||||
|
androidComponents {
|
||||||
|
onVariants { variant ->
|
||||||
|
val abiCodes = mapOf(
|
||||||
|
"armeabi-v7a" to 1,
|
||||||
|
"arm64-v8a" to 2,
|
||||||
|
"x86" to 3,
|
||||||
|
"x86_64" to 4
|
||||||
|
)
|
||||||
|
|
||||||
|
variant.outputs.forEach { output ->
|
||||||
|
val abiName = output.filters.find { it.filterType.name == "ABI" }?.identifier
|
||||||
|
val abiVersionCode = abiCodes[abiName] ?: 9 // Universal APK gets 9
|
||||||
|
output.versionCode.set(baseVersionCode * 1000 + abiVersionCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
|
@ -41,8 +41,7 @@ class WebAppInterface(private val context: MainActivity, private val webView: We
|
|||||||
|
|
||||||
// Security patterns for input validation
|
// Security patterns for input validation
|
||||||
private val UUID_PATTERN = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", Pattern.CASE_INSENSITIVE)
|
private val UUID_PATTERN = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", Pattern.CASE_INSENSITIVE)
|
||||||
private val SAFE_STRING_PATTERN = Pattern.compile("^[a-zA-Z0-9\s_\-.,:;!?()\[\]{}\"]*$")
|
private val SAFE_STRING_PATTERN = Pattern.compile("^[a-zA-Z0-9\\s_\\-.,:;!?()\\[\\]{}\\"]*$")
|
||||||
|
|
||||||
// Maximum length for input strings
|
// Maximum length for input strings
|
||||||
private val MAX_INPUT_LENGTH = 1000
|
private val MAX_INPUT_LENGTH = 1000
|
||||||
|
|
||||||
@ -108,17 +107,31 @@ class WebAppInterface(private val context: MainActivity, private val webView: We
|
|||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun copyToClipboard(message: String) {
|
fun copyToClipboard(message: String) {
|
||||||
|
// Validate input
|
||||||
|
if (!isValidInput(message, 10000)) { // Allow longer text for clipboard
|
||||||
|
Log.e(TAG, "Invalid input for copyToClipboard")
|
||||||
|
Toast.makeText(context, "Invalid content for clipboard", Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Limit clipboard content size for security
|
||||||
|
val truncatedMessage = if (message.length > 10000) {
|
||||||
|
message.substring(0, 10000) + "... (content truncated for security)"
|
||||||
|
} else {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
|
||||||
// Copy to clipboard
|
// Copy to clipboard
|
||||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
||||||
val clip = android.content.ClipData.newPlainText("RoboSats Data", message)
|
val clip = android.content.ClipData.newPlainText("RoboSats Data", truncatedMessage)
|
||||||
clipboard.setPrimaryClip(clip)
|
clipboard.setPrimaryClip(clip)
|
||||||
|
|
||||||
// Show a toast notification
|
// Show a toast notification
|
||||||
Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Log the action (don't log the content for privacy)
|
// Log the action (don't log the content for privacy)
|
||||||
Log.d(TAG, "Text copied to clipboard")
|
Log.d(TAG, "Text copied to clipboard (${truncatedMessage.length} chars)")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error copying to clipboard", e)
|
Log.e(TAG, "Error copying to clipboard", e)
|
||||||
Toast.makeText(context, "Failed to copy to clipboard", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Failed to copy to clipboard", Toast.LENGTH_SHORT).show()
|
||||||
@ -383,29 +396,6 @@ class WebAppInterface(private val context: MainActivity, private val webView: We
|
|||||||
resolvePromise(uuid, key)
|
resolvePromise(uuid, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
fun restart() {
|
|
||||||
try {
|
|
||||||
Log.d(TAG, "Restarting app...")
|
|
||||||
|
|
||||||
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
||||||
intent?.let {
|
|
||||||
it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
||||||
|
|
||||||
context.startActivity(it)
|
|
||||||
context.finish()
|
|
||||||
} ?: run {
|
|
||||||
Log.e(TAG, "Could not get launch intent for app restart")
|
|
||||||
Toast.makeText(context, "Failed to restart app", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error restarting app", e)
|
|
||||||
Toast.makeText(context, "Failed to restart app", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onWsMessage(path: String?, message: String?) {
|
private fun onWsMessage(path: String?, message: String?) {
|
||||||
val encodedMessage = encodeForJavaScript(message)
|
val encodedMessage = encodeForJavaScript(message)
|
||||||
safeEvaluateJavascript("javascript:window.AndroidRobosats.onWSMessage('$path', '$encodedMessage')")
|
safeEvaluateJavascript("javascript:window.AndroidRobosats.onWSMessage('$path', '$encodedMessage')")
|
||||||
|
Reference in New Issue
Block a user