Skip to content

Commit

Permalink
merge latest
Browse files Browse the repository at this point in the history
  • Loading branch information
atavism committed Aug 30, 2023
2 parents be38210 + 494bf88 commit 5118e6c
Show file tree
Hide file tree
Showing 24 changed files with 403 additions and 216 deletions.
18 changes: 7 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ permissions:
env:
GOPRIVATE: github.com/getlantern
S3_BUCKET: lantern
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
DATADOG_SITE: datadoghq.eu
jobs:
set-version:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -80,17 +82,6 @@ jobs:
run: |
git config --global url."https://${{ secrets.GH_TOKEN }}:[email protected]/".insteadOf "https://github.com/"
- name: Build Lantern core Android library
run: make android-lib

- name: Setup Sentry CLI
uses: mathieu-bour/setup-sentry-cli@v1
with:
version: latest
token: ${{ SECRETS.SENTRY_TOKEN }} # from GitHub secrets
organization: getlantern
project: android

- name: Setup JDK 11
uses: actions/setup-java@v3
with:
Expand Down Expand Up @@ -125,9 +116,14 @@ jobs:
fileDir: './android/app'
encodedString: ${{ secrets.KEYSTORE }}

- name: Install Datadog CI
run: npm install -g @datadog/datadog-ci

- name: Build Android installers
run: make package-android
env:
DD_APPLICATION_ID: ${{ secrets.DD_APPLICATION_ID }}
DD_CLIENT_TOKEN: ${{ secrets.DD_CLIENT_TOKEN }}
INTERSTITIAL_AD_UNIT_ID: "${{ secrets.INTERSTITIAL_AD_UNIT_ID }}"
VERSION: "${{ env.version }}"

Expand Down
63 changes: 40 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ ADB := $(call get-command,adb)
OPENSSL := $(call get-command,openssl)
GMSAAS := $(call get-command,gmsaas)
SENTRY := $(call get-command,sentry-cli)
DATADOGCI := $(call get-command,datadog-ci)
BASE64 := $(call get-command,base64)

GIT_REVISION_SHORTCODE := $(shell git rev-parse --short HEAD)
Expand Down Expand Up @@ -241,6 +242,10 @@ require-magick:
require-sentry:
@if [[ -z "$(SENTRY)" ]]; then echo 'Missing "sentry-cli" command. See sentry.io for installation instructions.'; exit 1; fi

.PHONY: require-datadog-ci
require-datadog-ci:
@if [[ -z "$(DATADOGCI)" ]]; then echo 'Missing "datadog-ci" command. See https://www.npmjs.com/package/@datadog/datadog-ci for installation instructions.'; exit 1; fi

release-autoupdate: require-version
@TAG_COMMIT=$$(git rev-list --abbrev-commit -1 $(TAG)) && \
if [[ -z "$$TAG_COMMIT" ]]; then \
Expand All @@ -263,7 +268,7 @@ $(ANDROID_LIB): $(GO_SOURCES)
gomobile bind \
-target=$(ANDROID_ARCH_GOMOBILE) \
-tags='headless lantern' -o=$(ANDROID_LIB) \
-androidapi=19 \
-androidapi=23 \
-ldflags="$(LDFLAGS)" \
$(GOMOBILE_EXTRA_BUILD_FLAGS) \
$(ANDROID_LIB_PKG)
Expand All @@ -282,27 +287,31 @@ $(MOBILE_TEST_APK) $(MOBILE_TESTS_APK): $(MOBILE_SOURCES) $(MOBILE_ANDROID_LIB)
-b $(MOBILE_DIR)/app/build.gradle \
:app:assembleAutoTestDebug :app:assembleAutoTestDebugAndroidTest

vault-secret:
vault-secret-%:
@SECRET=$(shell cd $$GOPATH/src/github.com/getlantern/lantern-cloud && bin/vault kv get -field=${*} ${VAULT_DD_SECRETS_PATH}); \
printf "$$SECRET"

vault-secret-base64:
@SECRET=$(shell cd $$GOPATH/src/github.com/getlantern/lantern-cloud && bin/vault kv get -field=$(VAULT_FIELD) $(VAULT_PATH)); \
echo "Retrieved secret: $$SECRET" 1>&2; \
printf "$$VAULT_FIELD=$$SECRET" | ${BASE64}

dart-defines-debug:
@DART_DEFINES=$(shell make vault-secret VAULT_FIELD=INTERSTITIAL_AD_UNIT_ID VAULT_PATH=secret/googleAds); \
@DART_DEFINES=$(shell make vault-secret-base64 VAULT_FIELD=INTERSTITIAL_AD_UNIT_ID VAULT_PATH=secret/googleAds); \
DART_DEFINES+=$(shell printf ',' && make vault-secret-base64 VAULT_FIELD=DD_APPLICATION_ID VAULT_PATH=secret/apps/datadog/android); \
DART_DEFINES+=$(shell printf ',' && make vault-secret-base64 VAULT_FIELD=DD_CLIENT_TOKEN VAULT_PATH=secret/apps/datadog/android); \
DART_DEFINES+=",$(CIBASE)"; \
echo "$$DART_DEFINES"

do-android-debug: $(MOBILE_SOURCES) $(MOBILE_ANDROID_LIB)
@ln -fs $(MOBILE_DIR)/gradle.properties . && \
DART_DEFINES=`make dart-defines-debug` && \
COUNTRY="$$COUNTRY" && \
PAYMENT_PROVIDER="$$PAYMENT_PROVIDER" && \
STAGING="$$STAGING" && \
STICKY_CONFIG="$$STICKY_CONFIG" && \
CI="$$CI" && \
echo "DART_DEFINES values: $$DART_DEFINES" && \
$(GRADLE) -PlanternVersion=$(DEBUG_VERSION) -Pdart-defines="$$DART_DEFINES" -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) -PplayVersion=$(FORCE_PLAY_VERSION) -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) -PlanternRevisionDate=$(REVISION_DATE) -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" -PdevelopmentMode="true" -Pci=$(CI) -b $(MOBILE_DIR)/app/build.gradle \
assembleProdDebug
CI="$$CI" && $(GRADLE) -Pdart-defines="$$DART_DEFINES" -PlanternVersion=$(DEBUG_VERSION) -PddClientToken=$$DD_CLIENT_TOKEN -PddApplicationID=$$DD_APPLICATION_ID \
-PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) \
-PplayVersion=$(FORCE_PLAY_VERSION) -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) \
-PlanternRevisionDate=$(REVISION_DATE) -PandroidArch=$(ANDROID_ARCH) \
-PandroidArchJava="$(ANDROID_ARCH_JAVA)" -PdevelopmentMode="true" \
-Pci=$(CI) -b $(MOBILE_DIR)/app/build.gradle assembleProdDebug

pubget:
@flutter pub get
Expand All @@ -321,38 +330,46 @@ dart-defines-release:
DART_DEFINES+=`printf ',' && $(CIBASE)`; \
printf $$DART_DEFINES

$(MOBILE_RELEASE_APK): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-sentry
$(MOBILE_RELEASE_APK): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-datadog-ci
echo $(MOBILE_ANDROID_LIB) && \
mkdir -p ~/.gradle && \
ln -fs $(MOBILE_DIR)/gradle.properties . && \
DD_CLIENT_TOKEN="$$DD_CLIENT_TOKEN" && \
DD_APPLICATION_ID="$$DD_APPLICATION_ID" && \
COUNTRY="$$COUNTRY" && \
STAGING="$$STAGING" && \
STICKY_CONFIG="$$STICKY_CONFIG" && \
PAYMENT_PROVIDER="$$PAYMENT_PROVIDER" && \
VERSION_CODE="$$VERSION_CODE" && \
DEVELOPMENT_MODE="$$DEVELOPMENT_MODE" && \
DART_DEFINES=`make dart-defines-release` && \
$(GRADLE) -PlanternVersion=$$VERSION -PlanternRevisionDate=$(REVISION_DATE) -Pdart-defines="$$DART_DEFINES" -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) -PplayVersion=$(FORCE_PLAY_VERSION) -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) -PversionCode=$(VERSION_CODE) -PdevelopmentMode=$(DEVELOPMENT_MODE) -b $(MOBILE_DIR)/app/build.gradle \
assembleProdSideload && \
sentry-cli upload-dif --wait -o getlantern -p android build/app/intermediates/merged_native_libs/prodSideload/out/lib && \
$(GRADLE) -PlanternVersion=$$VERSION -Pdart-defines="$$DART_DEFINES" -PlanternRevisionDate=$(REVISION_DATE) -PddClientToken="$(DD_CLIENT_TOKEN)" \
-PddApplicationID="$(DD_APPLICATION_ID)" -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" -PproServerUrl=$(PRO_SERVER_URL) \
-PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) -PplayVersion=$(FORCE_PLAY_VERSION) -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) \
-PversionCode=$(VERSION_CODE) -PdevelopmentMode=$(DEVELOPMENT_MODE) -b $(MOBILE_DIR)/app/build.gradle assembleProdSideload && \
datadog-ci flutter-symbols upload --service-name lantern-android --dart-symbols-location build/app/intermediates/merged_native_libs/prodSideload/out/lib \
--android-mapping-location build/app/outputs/mapping/prodSideload/mapping.txt --android-mapping --ios-dsyms && \
cp $(MOBILE_ANDROID_RELEASE) $(MOBILE_RELEASE_APK) && \
cat $(MOBILE_RELEASE_APK) | bzip2 > lantern_update_android_arm.bz2


$(MOBILE_BUNDLE): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-sentry
$(MOBILE_BUNDLE): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-datadog-ci
@mkdir -p ~/.gradle && \
ln -fs $(MOBILE_DIR)/gradle.properties . && \
DD_CLIENT_TOKEN="$$DD_CLIENT_TOKEN" && \
DD_APPLICATION_ID="$$DD_APPLICATION_ID" && \
COUNTRY="$$COUNTRY" && \
STAGING="$$STAGING" && \
STICKY_CONFIG="$$STICKY_CONFIG" && \
PAYMENT_PROVIDER="$$PAYMENT_PROVIDER" && \
$(GRADLE) -PlanternVersion=$$VERSION -PlanternRevisionDate=$(REVISION_DATE) -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) -PplayVersion=true -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) -b $(MOBILE_DIR)/app/build.gradle \
bundlePlay && \
sentry-cli upload-dif --wait -o getlantern -p android build/app/intermediates/merged_native_libs/prodPlay/out/lib && \
$(GRADLE) -PlanternVersion=$$VERSION -PlanternRevisionDate=$(REVISION_DATE) -PandroidArch=$(ANDROID_ARCH) -PandroidArchJava="$(ANDROID_ARCH_JAVA)" \
-PddClientToken=$(DD_CLIENT_TOKEN) -PddApplicationID=$(DD_APPLICATION_ID) -PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) \
-Pcountry=$(COUNTRY) -PplayVersion=true -PuseStaging=$(STAGING) -PstickyConfig=$(STICKY_CONFIG) -b $(MOBILE_DIR)/app/build.gradle bundlePlay && \
datadog-ci flutter-symbols upload --service-name lantern-android --dart-symbols-location build/app/intermediates/merged_native_libs/prodPlay/out/lib \
--android-mapping-location build/app/outputs/mapping/prodPlay/mapping.txt --ios-dsyms && \
cp $(MOBILE_ANDROID_BUNDLE) $(MOBILE_BUNDLE)


android-debug: $(MOBILE_DEBUG_APK)
android-debug:
DD_APPLICATION_ID=`make vault-secret-DD_APPLICATION_ID` DD_CLIENT_TOKEN=`make vault-secret-DD_CLIENT_TOKEN` make $(MOBILE_DEBUG_APK)

android-release: pubget $(MOBILE_RELEASE_APK)

Expand All @@ -364,7 +381,7 @@ android-debug-install: $(MOBILE_DEBUG_APK)
android-release-install: $(MOBILE_RELEASE_APK)
$(ADB) install -r $(MOBILE_RELEASE_APK)

package-android: require-version clean
package-android: pubget require-version
@ANDROID_ARCH=all make android-release && \
ANDROID_ARCH=all make android-bundle && \
echo "-> $(MOBILE_RELEASE_APK)"
Expand Down
50 changes: 29 additions & 21 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
plugins {
id "io.sentry.android.gradle" version "3.4.2"
id 'com.android.application'
id 'kotlin-android'
id 'org.jlleitschuh.gradle.ktlint'
id 'org.jetbrains.kotlin.android'
id 'kotlin-parcelize'
id 'kotlin-kapt'
id 'com.google.protobuf'
id("com.datadoghq.dd-sdk-android-gradle-plugin") version "1.10.0"
}

def localProperties = new Properties()
Expand All @@ -19,7 +19,10 @@ if (localPropertiesFile.exists()) {

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
flutterRoot = System.env.FLUTTER_ROOT
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
Expand Down Expand Up @@ -177,6 +180,8 @@ android {
buildConfigField "boolean", "STICKY_CONFIG", getBoolean("stickyConfig")
buildConfigField "boolean", "STAGING", getBoolean("useStaging")
buildConfigField "boolean", "PLAY_VERSION", getBoolean("playVersion")
buildConfigField "String", "DD_CLIENT_TOKEN", ddClientToken()
buildConfigField "String", "DD_APPLICATION_ID", ddApplicationID()
buildConfigField "String", "COUNTRY", userCountry()
buildConfigField "String", "PAYMENT_PROVIDER", paymentProvider()
buildConfigField "String", "PRO_SERVER_URL", proServerUrl()
Expand All @@ -195,6 +200,8 @@ android {
buildConfigField "boolean", "STICKY_CONFIG", getBoolean("stickyConfig")
buildConfigField "boolean", "STAGING", getBoolean("useStaging")
buildConfigField "boolean", "PLAY_VERSION", getBoolean("playVersion")
buildConfigField "String", "DD_CLIENT_TOKEN", ddClientToken()
buildConfigField "String", "DD_APPLICATION_ID", ddApplicationID()
buildConfigField "String", "COUNTRY", userCountry()
buildConfigField "String", "SIGNING_CERTIFICATE_SHA256", "\"\""
buildConfigField "String", "PAYMENT_PROVIDER", paymentProvider()
Expand All @@ -213,6 +220,8 @@ android {
buildConfigField "boolean", "STICKY_CONFIG", getBoolean("stickyConfig")
buildConfigField "boolean", "STAGING", getBoolean("useStaging")
buildConfigField "boolean", "PLAY_VERSION", getBoolean("playVersion")
buildConfigField "String", "DD_CLIENT_TOKEN", ddClientToken()
buildConfigField "String", "DD_APPLICATION_ID", ddApplicationID()
buildConfigField "String", "COUNTRY", userCountry()
buildConfigField "String", "SIGNING_CERTIFICATE_SHA256", "\"108f612ae55354078ec12b10bb705362840d48fa78b9262c11b6d0adeff6f289\""
buildConfigField "String", "PAYMENT_PROVIDER", paymentProvider()
Expand Down Expand Up @@ -318,6 +327,22 @@ def getInt(name) {
return value.toInteger()
}

def ddApplicationID() {
def value = project.getProperties().get("ddApplicationID")
if (value == null || !value?.trim()) {
return "\"\""
}
return String.format("\"%s\"", value)
}

def ddClientToken() {
def value = project.getProperties().get("ddClientToken")
if (value == null || !value?.trim()) {
return "\"\""
}
return String.format("\"%s\"", value)
}

def userCountry() {
def value = project.getProperties().get("country")
if (value == null || !value?.trim()) {
Expand Down Expand Up @@ -423,6 +448,8 @@ dependencies {

implementation 'com.stripe:stripe-android:20.17.0'

implementation 'com.datadoghq:dd-sdk-android:1.19.3'

annotationProcessor "org.androidannotations:androidannotations:$androidAnnotationsVersion"
implementation("org.androidannotations:androidannotations-api:$androidAnnotationsVersion")
kapt "org.androidannotations:androidannotations:$androidAnnotationsVersion"
Expand Down Expand Up @@ -451,22 +478,3 @@ dependencies {
}

apply plugin: 'com.google.gms.google-services'

sentry {
// Enables or disables the automatic upload of mapping files
// during a build. If you disable this, you'll need to manually
// upload the mapping files with sentry-cli when you do a release.
autoUpload = true

// Disables or enables the automatic configuration of Native Symbols
// for Sentry. This executes sentry-cli automatically so
// you don't need to do it manually.
// Default is disabled.
uploadNativeSymbols = true

// Does or doesn't include the source code of native code for Sentry.
// This executes sentry-cli with the --include-sources param. automatically so
// you don't need to do it manually.
// Default is disabled.
includeNativeSources = false
}
4 changes: 4 additions & 0 deletions android/app/src/main/kotlin/io/lantern/model/SessionModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.getlantern.lantern.R
import org.getlantern.lantern.activity.FreeKassaActivity_
import org.getlantern.lantern.activity.WebViewActivity_
import org.getlantern.mobilesdk.model.IssueReporter
import org.getlantern.lantern.datadog.Datadog
import org.getlantern.lantern.model.LanternHttpClient
import org.getlantern.lantern.model.LanternHttpClient.ProCallback
import org.getlantern.lantern.model.LanternHttpClient.ProUserCallback
Expand Down Expand Up @@ -157,6 +158,9 @@ class SessionModel(
activity.startActivity(intent)
}
}
"trackUserAction" -> {
Datadog.trackUserClick(call.argument("message")!!)
}
"acceptTerms" -> {
LanternApp.getSession().acceptTerms()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package org.getlantern.lantern
import android.app.Application
import android.content.Context
import android.os.StrictMode
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
import org.getlantern.lantern.datadog.Datadog
import org.getlantern.lantern.datadog.FlutterExcludingComponentPredicate
import org.getlantern.lantern.model.InAppBilling
import org.getlantern.lantern.model.LanternHttpClient
import org.getlantern.lantern.model.LanternSessionManager
import org.getlantern.lantern.util.debugOnly
import org.getlantern.lantern.util.LanternProxySelector
import org.getlantern.lantern.util.SentryUtil
import org.getlantern.mobilesdk.Logger
import org.getlantern.mobilesdk.util.HttpClient

open class LanternApp : Application() {
Expand Down Expand Up @@ -39,12 +42,13 @@ open class LanternApp : Application() {

override fun onCreate() {
super.onCreate()
SentryUtil.enableGoPanicEnrichment(this)

// Necessary to locate a back arrow resource we use from the
// support library. See http://stackoverflow.com/questions/37615470/support-library-vectordrawable-resourcesnotfoundexception
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
appContext = applicationContext
session = LanternSessionManager(this)
Datadog.initialize()
LanternProxySelector(session)

if (session.isPlayVersion) inAppBilling = InAppBilling(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.lantern.model.MessagingModel
Expand All @@ -24,6 +25,7 @@ import io.lantern.model.VpnModel
import kotlinx.coroutines.*
import okhttp3.Response
import org.getlantern.lantern.activity.WebViewActivity_
import org.getlantern.lantern.datadog.Datadog
import org.getlantern.lantern.event.EventManager
import org.getlantern.lantern.model.AccountInitializationStatus
import org.getlantern.lantern.model.Bandwidth
Expand Down Expand Up @@ -77,7 +79,7 @@ class MainActivity :
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
val start = System.currentTimeMillis()
super.configureFlutterEngine(flutterEngine)

FlutterEngineCache.getInstance().put("datadoghq_engine", flutterEngine)
messagingModel = MessagingModel(this, flutterEngine)
vpnModel = VpnModel(this, flutterEngine, ::switchLantern)
sessionModel = SessionModel(this, flutterEngine)
Expand All @@ -87,6 +89,7 @@ class MainActivity :
eventManager = object : EventManager("lantern_event_channel", flutterEngine) {
override fun onListen(event: Event) {
if (LanternApp.getSession().lanternDidStart()) {
flutterNavigation.invokeMethod("initDatadog", null)
fetchLoConf()
Logger.debug(
TAG,
Expand Down Expand Up @@ -300,7 +303,7 @@ class MainActivity :
private fun updateUserData() {
lanternClient.userData(object : ProUserCallback {
override fun onFailure(throwable: Throwable?, error: ProError?) {
Logger.error(TAG, "Unable to fetch user data: $error", throwable)
Datadog.addError("Unable to fetch user data: $error", throwable)
}

override fun onSuccess(response: Response, user: ProUser) {
Expand All @@ -325,7 +328,7 @@ class MainActivity :
private fun updatePlans() {
lanternClient.plans(object : PlansCallback {
override fun onFailure(throwable: Throwable?, error: ProError?) {
Logger.error(TAG, "Unable to fetch user plans: $error", throwable)
Datadog.addError("Unable to fetch user plans: $error", throwable)
}

override fun onSuccess(proPlans: Map<String, ProPlan>) {
Expand All @@ -342,7 +345,7 @@ class MainActivity :
private fun updatePaymentMethods() {
lanternClient.plansV3(object : PlansV3Callback {
override fun onFailure(throwable: Throwable?, error: ProError?) {
Logger.error(TAG, "Unable to fetch user plans: $error", throwable)
Datadog.addError("Unable to fetch payment methods: $error", throwable)
}

override fun onSuccess(
Expand Down
Loading

0 comments on commit 5118e6c

Please sign in to comment.