Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 75 additions & 2 deletions .github/workflows/release_on_tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,91 @@ on:
push:
tags:
- "*"
release:
types: [published]

permissions:
contents: write
packages: read

env:
RELEASE_TAG: ${{ github.event.release.tag_name || github.ref_name }}

jobs:
create-release:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Create release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
name: ${{ env.RELEASE_TAG }}
tag_name: ${{ env.RELEASE_TAG }}
draft: false
generate_release_notes: true

build-fdroid-apk:
name: Build F-Droid APK
needs: create-release
if: ${{ always() && (github.event_name == 'release' || needs.create-release.result == 'success') }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ env.RELEASE_TAG }}

- name: Set up JDK
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.0.0
with:
distribution: temurin
java-version: "17"

- name: Set up Rust
uses: ./.github/actions/setup-rust-ci
with:
shared-key: fdroid-release

- name: Install Linux build dependencies
run: sudo apt-get update && sudo apt-get install -y build-essential

- name: Install Android toolchains
working-directory: android
run: |
just install-toolchains
just install-ndk
- name: Prepare signing
env:
ANDROID_FDROID_KEYSTORE_CONTENT_BASE64: ${{ secrets.ANDROID_FDROID_KEYSTORE_CONTENT_BASE64 }}
run: |
set -euo pipefail
: "${ANDROID_FDROID_KEYSTORE_CONTENT_BASE64:?ANDROID_FDROID_KEYSTORE_CONTENT_BASE64 is required}"
touch android/local.properties
echo -n "$ANDROID_FDROID_KEYSTORE_CONTENT_BASE64" | base64 --decode > android/app/fdroid-release.keystore
- name: Build F-Droid APK
working-directory: android
env:
ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_FDROID_KEYSTORE_ALIAS }}
ANDROID_KEYSTORE_FILENAME: fdroid-release.keystore
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_FDROID_KEYSTORE_PASSWORD }}
GPR_USERNAME: ${{ github.actor }}
GPR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: just release-fdroid

- name: Prepare release asset
id: asset
run: |
set -euo pipefail
apk="android/app/build/outputs/apk/fdroid/release/app-fdroid-release.apk"
asset="android/app/build/outputs/apk/fdroid/release/gem_wallet_fdroid_${RELEASE_TAG}.apk"
test -f "$apk"
cp "$apk" "$asset"
echo "path=$asset" >> "$GITHUB_OUTPUT"
- name: Upload F-Droid APK
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
tag_name: ${{ env.RELEASE_TAG }}
files: ${{ steps.asset.outputs.path }}
78 changes: 60 additions & 18 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,38 @@ plugins {
id("kotlinx-serialization")
id("com.google.devtools.ksp")
id("androidx.room")
id("com.google.gms.google-services")
}

val googleServicesExcludedFlavors = setOf("fdroid")
val googleServicesExcludedTaskPrefixes = googleServicesExcludedFlavors.map { flavor ->
"process${flavor.replaceFirstChar { it.uppercase() }}"
}
val googleServicesTasks = gradle.startParameter.taskNames
.map { it.substringAfterLast(":").lowercase() }
.filterNot { it == "clean" }
val shouldApplyGoogleServices = file("google-services.json").isFile &&
(
googleServicesTasks.isEmpty() ||
googleServicesTasks.any { task ->
googleServicesExcludedFlavors.none { flavor -> task.contains(flavor) } ||
task in setOf("assemble", "build", "bundle") ||
task == "assemblerelease" ||
task == "bundlerelease"
}
)

if (shouldApplyGoogleServices) {
apply(plugin = "com.google.gms.google-services")

tasks.configureEach {
if (
name.startsWith("process") &&
name.endsWith("GoogleServices") &&
googleServicesExcludedTaskPrefixes.any { prefix -> name.startsWith(prefix) }
) {
enabled = false
}
}
}

repositories {
Expand All @@ -19,7 +50,7 @@ repositories {
android {
namespace = "com.gemwallet.android"
compileSdk = 37
ndkVersion = "28.1.13356709"
ndkVersion = libs.versions.androidNdk.get()

val channelDimension by extra("channel")
flavorDimensions.add(channelDimension)
Expand All @@ -35,6 +66,7 @@ android {
vectorDrawables {
useSupportLibrary = true
}
buildConfigField("boolean", "WALLET_CONNECT_ENABLED", "true")

splits {
abi {
Expand All @@ -57,7 +89,12 @@ android {

create("fdroid") {
dimension = channelDimension
ndk {
abiFilters.add("armeabi-v7a")
abiFilters.add("arm64-v8a")
}
buildConfigField("String", "UPDATE_URL", "\"\"")
buildConfigField("boolean", "WALLET_CONNECT_ENABLED", "false")
}
create("huawei") {
dimension = channelDimension
Expand Down Expand Up @@ -138,7 +175,10 @@ android {
}

getByName("release") {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
Expand Down Expand Up @@ -289,27 +329,29 @@ dependencies {

implementation(libs.reorderable)

// Google Play
"googleImplementation"(project(":flavors:fcm"))
"googleImplementation"(project(":flavors:google-review"))
// Solana Store
"solanaImplementation"(project(":flavors:fcm"))
"solanaImplementation"(project(":flavors:review-stub"))
// Universal
"universalImplementation"(project(":flavors:fcm"))
"universalImplementation"(project(":flavors:google-review"))
// Samsung
"samsungImplementation"(project(":flavors:fcm"))
"samsungImplementation"(project(":flavors:review-stub"))
if (System.getenv("FDROID_BUILD") != "true") {
// Google Play
"googleImplementation"(project(":flavors:fcm"))
"googleImplementation"(project(":flavors:google-review"))
// Solana Store
"solanaImplementation"(project(":flavors:fcm"))
"solanaImplementation"(project(":flavors:review-stub"))
// Universal
"universalImplementation"(project(":flavors:fcm"))
"universalImplementation"(project(":flavors:google-review"))
// Samsung
"samsungImplementation"(project(":flavors:fcm"))
"samsungImplementation"(project(":flavors:review-stub"))
// emerald
"emeraldImplementation"(project(":flavors:fcm"))
"emeraldImplementation"(project(":flavors:review-stub"))
}
// huawei
"huaweiImplementation"(project(":flavors:pushes-stub"))
"huaweiImplementation"(project(":flavors:review-stub"))
// fdroid
"fdroidImplementation"(project(":flavors:pushes-stub"))
"fdroidImplementation"(project(":flavors:review-stub"))
// emerald
"emeraldImplementation"(project(":flavors:fcm"))
"emeraldImplementation"(project(":flavors:review-stub"))

// Preview
debugImplementation(libs.androidx.ui.tooling)
Expand Down
13 changes: 8 additions & 5 deletions android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,24 @@
# public *;
#}

# Preserve stack traces and fix R8 non-deterministic map-id for reproducible builds.
-keepattributes SourceFile,LineNumberTable
# Keep SourceFile stable and avoid path-derived R8 SourceFile names.
-keepattributes SourceFile
-renamesourcefileattribute SourceFile

-verbose
#-dontobfuscate
-ignorewarnings

# These lines allow optimisation whilst preserving stack traces
-optimizations !code/allocation/variable
-optimizations !class/unboxing/enum
# Disable R8 optimization to keep pg-map-id and DEX output stable across clean builds.
-dontoptimize

# Keep method names for stack traces while allowing shrinking.
-keep,allowshrinking,allowoptimization class * { <methods>; }
-keepattributes Signature

-dontwarn com.google.firebase.analytics.connector.AnalyticsConnector
-dontwarn com.google.firebase.**
-dontwarn com.google.android.gms.**

-keep class com.gemwallet.android.** { *; }
-keep class com.sun.jna.** { *; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class MainActivity : FragmentActivity(), AuthRequester {
pendingNavigation = pendingNavigation,
systemAuthEnrollmentMissing = systemAuthEnrollmentMissing,
walletConnectViewModel = walletConnectViewModel,
walletConnectEnabled = BuildConfig.WALLET_CONNECT_ENABLED,
onSystemAuthRequired = systemAuthenticator::authenticate,
onIntentConsumed = viewModel::consumePendingNavigation,
onOpenSystemAuthSettings = systemAuthenticator::openSettings,
Expand Down
26 changes: 17 additions & 9 deletions android/app/src/main/kotlin/com/gemwallet/android/MainContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import com.gemwallet.android.model.AuthState
import com.gemwallet.android.ui.WalletApp
import com.gemwallet.android.ui.models.actions.AssetIdAction
import com.gemwallet.android.ui.theme.WalletTheme

@Composable
Expand All @@ -19,6 +20,7 @@ internal fun MainContent(
pendingNavigation: PendingNavigation?,
systemAuthEnrollmentMissing: Boolean,
walletConnectViewModel: WalletConnectViewModel,
walletConnectEnabled: Boolean,
onSystemAuthRequired: () -> Unit,
onIntentConsumed: () -> Unit,
onOpenSystemAuthSettings: () -> Unit,
Expand All @@ -32,7 +34,11 @@ internal fun MainContent(
val isWalletUnlocked = state.initialAuth == AuthState.Success
val isEnrollmentRequired = state.initialAuth == AuthState.Required && systemAuthEnrollmentMissing
val unlockedPendingRoutes = if (isWalletUnlocked) pendingRoutes else emptyList()
val walletConnectOverlay = rememberWalletConnectOverlay(walletConnectViewModel, onWalletConnectError)
val walletConnectOverlay: @Composable (AssetIdAction) -> Unit = if (walletConnectEnabled) {
rememberWalletConnectOverlay(walletConnectViewModel, onWalletConnectError)
} else {
remember { { _: AssetIdAction -> } }
}
var isWalletContentReady by remember { mutableStateOf(state.hasUnlockedApp) }
val onWalletContentReady: () -> Unit = remember { { isWalletContentReady = true } }
val shouldShowLockedSplash = !isWalletUnlocked || !isWalletContentReady
Expand Down Expand Up @@ -62,13 +68,15 @@ internal fun MainContent(
}
}

WalletConnectPairingToast(
visible = state.isWalletConnectPairingToastVisible,
onShown = onWalletConnectPairingToastShown,
)
WalletConnectErrorDialog(
error = state.walletConnectError,
onDismiss = onWalletConnectErrorDismiss,
)
if (walletConnectEnabled) {
WalletConnectPairingToast(
visible = state.isWalletConnectPairingToastVisible,
onShown = onWalletConnectPairingToastShown,
)
WalletConnectErrorDialog(
error = state.walletConnectError,
onDismiss = onWalletConnectErrorDismiss,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ class MainViewModel @Inject constructor(

private val walletConnectHandler = object : PendingNavigationCoordinator.WalletConnectHandler {
override fun onPairing(uri: String) = addPairing(uri)
override fun onRequest() = showWalletConnectPairingToast()
override fun onRequest() {
if (BuildConfig.WALLET_CONNECT_ENABLED) {
showWalletConnectPairingToast()
}
}
}

init {
Expand Down Expand Up @@ -157,6 +161,9 @@ class MainViewModel @Inject constructor(
}

private fun addPairing(uri: String) {
if (!BuildConfig.WALLET_CONNECT_ENABLED) {
return
}
showWalletConnectPairingToast()
viewModelScope.launch(Dispatchers.IO) {
bridgesRepository.addPairing(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.gemwallet.android.BuildConfig
import com.gemwallet.android.features.activities.presents.list.TransactionsNavScreen
import com.gemwallet.android.features.assets.viewmodels.AssetsViewModel
import com.gemwallet.android.features.assets.views.AssetsScreen
Expand Down Expand Up @@ -223,6 +224,7 @@ fun MainScreen(
scrollState = settingsScrollState,
onSecurity = navigator::openSecurity,
onBridges = navigator::openBridgeConnections,
walletConnectAvailable = BuildConfig.WALLET_CONNECT_ENABLED,
onDevelop = navigator::openDevelop,
onWallets = navigator::openWallets,
onNotifications = navigator::openNotifications,
Expand Down
8 changes: 6 additions & 2 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ buildscript {
gradlePluginPortal()
google()
mavenCentral()
mavenLocal()
}
dependencies {
classpath(libs.gradle)
Expand All @@ -20,6 +19,8 @@ plugins {
alias(libs.plugins.compose.compiler) apply false
}

val fdroidBuild = System.getenv("FDROID_BUILD") == "true"

allprojects {
repositories {
val propFile = File(rootDir.absolutePath, "local.properties")
Expand All @@ -33,7 +34,6 @@ allprojects {
}
google()
mavenCentral()
mavenLocal()
maven { url = uri("https://jitpack.io") }
}

Expand All @@ -47,6 +47,10 @@ subprojects {
lockAllConfigurations()
}
configurations.configureEach {
if (fdroidBuild) {
exclude(group = "com.google.firebase")
exclude(group = "com.google.android.gms")
}
resolutionStrategy.activateDependencyLocking()
}
}
Expand Down
Loading