Skip to content

Commit

Permalink
Allow setting publishable key after FlowController instantiation. (#3723
Browse files Browse the repository at this point in the history
)
  • Loading branch information
brnunes-stripe authored May 14, 2021
1 parent a105390 commit ac992e7
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 128 deletions.
7 changes: 1 addition & 6 deletions paymentsheet-example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ def getBackendUrl() {
return getValue('STRIPE_PAYMENTSHEET_EXAMPLE_BACKEND_URL')
}

def getPublishableKey() {
return getValue('STRIPE_PAYMENTSHEET_EXAMPLE_PUBLISHABLE_KEY')
}

private def getValue(key) {
// first try to get the value from Gradle properties
// see https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
Expand Down Expand Up @@ -80,8 +76,7 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

manifestPlaceholders = [
BACKEND_URL: getBackendUrl(),
PUBLISHABLE_KEY: getPublishableKey()
BACKEND_URL: getBackendUrl()
]
}

Expand Down
4 changes: 0 additions & 4 deletions paymentsheet-example/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package="com.stripe.android.paymentsheet.example">

<application
android:name=".PaymentSheetExampleApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
Expand All @@ -15,9 +14,6 @@
<meta-data
android:name="com.stripe.android.paymentsheet.example.metadata.backend_url"
android:value="${BACKEND_URL}" />
<meta-data
android:name="com.stripe.android.paymentsheet.example.metadata.publishable_key"
android:value="${PUBLISHABLE_KEY}" />

<activity
android:name=".MainActivity"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,12 @@ import android.content.pm.PackageManager
class Settings(context: Context) {
private val appContext = context.applicationContext
private val backendMetadata = getMetadata(METADATA_KEY_BACKEND_URL_KEY)
private val publishableKeyMetadata = getMetadata(METADATA_KEY_PUBLISHABLE_KEY)

val backendUrl: String
get() {
return backendMetadata ?: BASE_URL
}

val publishableKey: String
get() {
return publishableKeyMetadata ?: PUBLISHABLE_KEY
}

private fun getMetadata(key: String): String? {
return appContext.packageManager
.getApplicationInfo(appContext.packageName, PackageManager.GET_META_DATA)
Expand All @@ -40,16 +34,7 @@ class Settings(context: Context) {
*/
private const val BASE_URL = "put your base url here"

/**
* Note: only necessary if not configured via `gradle.properties`.
*
* Set to publishable key from https://dashboard.stripe.com/test/apikeys
*/
private const val PUBLISHABLE_KEY = "pk_test_your_key_goes_here"

private const val METADATA_KEY_BACKEND_URL_KEY =
"com.stripe.android.paymentsheet.example.metadata.backend_url"
private const val METADATA_KEY_PUBLISHABLE_KEY =
"com.stripe.android.paymentsheet.example.metadata.publishable_key"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ internal abstract class BasePaymentSheetActivity : AppCompatActivity() {
null
}

// Re-initing here because the ExampleApplication inits with the key from
// gradle properties
// Init PaymentConfiguration with the publishable key returned from the backend,
// which will be used on all Stripe API calls
PaymentConfiguration.init(this, checkoutResponse.publishableKey)

onSuccess(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.stripe.android.paymentsheet.flowcontroller

import android.content.Context
import android.os.Parcelable
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.google.android.gms.common.api.Status
import com.stripe.android.PaymentConfiguration
import com.stripe.android.PaymentController
import com.stripe.android.PaymentIntentResult
import com.stripe.android.PaymentRelayContract
import com.stripe.android.StripeIntentResult
Expand All @@ -13,6 +16,7 @@ import com.stripe.android.googlepay.StripeGooglePayContract
import com.stripe.android.googlepay.StripeGooglePayEnvironment
import com.stripe.android.model.StripeIntent
import com.stripe.android.networking.ApiRequest
import com.stripe.android.networking.StripeApiRepository
import com.stripe.android.payments.DefaultReturnUrl
import com.stripe.android.payments.PaymentFlowResult
import com.stripe.android.payments.PaymentFlowResultProcessor
Expand All @@ -33,6 +37,8 @@ import com.stripe.android.paymentsheet.model.PaymentOptionFactory
import com.stripe.android.paymentsheet.model.PaymentSelection
import com.stripe.android.paymentsheet.model.SavedSelection
import com.stripe.android.paymentsheet.model.SetupIntentClientSecret
import com.stripe.android.paymentsheet.repositories.PaymentMethodsApiRepository
import com.stripe.android.paymentsheet.repositories.StripeIntentRepository
import com.stripe.android.view.AuthActivityStarter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -42,6 +48,7 @@ import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize

internal class DefaultFlowController internal constructor(
private val appContext: Context,
viewModelStoreOwner: ViewModelStoreOwner,
private val lifecycleScope: CoroutineScope,
activityLauncherFactory: ActivityLauncherFactory,
Expand All @@ -50,10 +57,8 @@ internal class DefaultFlowController internal constructor(
private val paymentOptionFactory: PaymentOptionFactory,
private val flowControllerInitializer: FlowControllerInitializer,
paymentControllerFactory: PaymentControllerFactory,
private val paymentFlowResultProcessor: PaymentFlowResultProcessor,
paymentFlowResultProcessorFactory: (String, StripeApiRepository) -> PaymentFlowResultProcessor,
private val eventReporter: EventReporter,
private val publishableKey: String,
private val stripeAccountId: String?,
private val sessionId: SessionId,
private val defaultReturnUrl: DefaultReturnUrl,
private val paymentOptionCallback: PaymentOptionCallback,
Expand Down Expand Up @@ -101,11 +106,34 @@ internal class DefaultFlowController internal constructor(
private val viewModel =
ViewModelProvider(viewModelStoreOwner)[FlowControllerViewModel::class.java]

private val paymentController = paymentControllerFactory.create(
paymentRelayLauncher = paymentRelayLauncher,
paymentBrowserAuthLauncher = paymentBrowserAuthLauncher,
stripe3ds2ChallengeLauncher = stripe3ds2ChallengeLauncher
)
// The properties below are lazily initialized to allow the developer to set the publishableKey
// and stripeAccountId in PaymentConfiguration any time before configuring the FlowController
// through configureWithPaymentIntent or configureWithSetupIntent.

private val paymentConfiguration: PaymentConfiguration by lazy {
PaymentConfiguration.getInstance(appContext)
}

private val stripeApiRepository: StripeApiRepository by lazy {
StripeApiRepository(
appContext,
paymentConfiguration.publishableKey
)
}

private val paymentFlowResultProcessor: PaymentFlowResultProcessor by lazy {
paymentFlowResultProcessorFactory(paymentConfiguration.publishableKey, stripeApiRepository)
}

private val paymentController: PaymentController by lazy {
paymentControllerFactory.create(
paymentConfiguration.publishableKey,
stripeApiRepository,
paymentRelayLauncher = paymentRelayLauncher,
paymentBrowserAuthLauncher = paymentBrowserAuthLauncher,
stripe3ds2ChallengeLauncher = stripe3ds2ChallengeLauncher
)
}

override fun configureWithPaymentIntent(
paymentIntentClientSecret: String,
Expand Down Expand Up @@ -139,6 +167,20 @@ internal class DefaultFlowController internal constructor(
lifecycleScope.launch {
val result = flowControllerInitializer.init(
clientSecret,
StripeIntentRepository.Api(
stripeRepository = stripeApiRepository,
requestOptions = ApiRequest.Options(
paymentConfiguration.publishableKey,
paymentConfiguration.stripeAccountId
),
workContext = Dispatchers.IO
),
PaymentMethodsApiRepository(
stripeRepository = stripeApiRepository,
publishableKey = paymentConfiguration.publishableKey,
stripeAccountId = paymentConfiguration.stripeAccountId,
workContext = Dispatchers.IO
),
configuration
)

Expand All @@ -161,7 +203,9 @@ internal class DefaultFlowController internal constructor(
viewModel.initData
}.getOrElse {
error(
"FlowController must be successfully initialized using configure() before calling presentPaymentOptions()"
"FlowController must be successfully initialized using " +
"configureWithPaymentIntent() or configureWithSetupIntent() " +
"before calling presentPaymentOptions()"
)
}

Expand All @@ -183,7 +227,9 @@ internal class DefaultFlowController internal constructor(
viewModel.initData
}.getOrElse {
error(
"FlowController must be successfully initialized using configure() before calling confirmPayment()"
"FlowController must be successfully initialized using " +
"configureWithPaymentIntent() or configureWithSetupIntent() " +
"before calling presentPaymentOptions()"
)
}

Expand Down Expand Up @@ -233,8 +279,8 @@ internal class DefaultFlowController internal constructor(
authHostSupplier(),
confirmParams,
ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = stripeAccountId
apiKey = paymentConfiguration.publishableKey,
stripeAccount = paymentConfiguration.stripeAccountId
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,37 @@ import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext

internal class DefaultFlowControllerInitializer(
private val stripeIntentRepository: StripeIntentRepository,
private val paymentMethodsRepository: PaymentMethodsRepository,
private val prefsRepositoryFactory: (String, Boolean) -> PrefsRepository,
private val isGooglePayReadySupplier: suspend (PaymentSheet.GooglePayConfiguration.Environment?) -> Boolean,
private val workContext: CoroutineContext
) : FlowControllerInitializer {
private val paymentIntentValidator = PaymentIntentValidator()

private lateinit var stripeIntentRepository: StripeIntentRepository
private lateinit var paymentMethodsRepository: PaymentMethodsRepository

override suspend fun init(
clientSecret: ClientSecret,
configuration: PaymentSheet.Configuration?
stripeIntentRepository: StripeIntentRepository,
paymentMethodsRepository: PaymentMethodsRepository,
paymentSheetConfiguration: PaymentSheet.Configuration?
) = withContext(workContext) {
this@DefaultFlowControllerInitializer.stripeIntentRepository = stripeIntentRepository
this@DefaultFlowControllerInitializer.paymentMethodsRepository = paymentMethodsRepository

val isGooglePayReady =
configuration?.let { isGooglePayReadySupplier(it.googlePay?.environment) } ?: false
configuration?.customer?.let { customerConfig ->
paymentSheetConfiguration?.let { isGooglePayReadySupplier(it.googlePay?.environment) }
?: false
paymentSheetConfiguration?.customer?.let { customerConfig ->
createWithCustomer(
clientSecret,
customerConfig,
configuration,
paymentSheetConfiguration,
isGooglePayReady
)
} ?: createWithoutCustomer(
clientSecret,
configuration,
paymentSheetConfiguration,
isGooglePayReady
)
}
Expand Down
Loading

0 comments on commit ac992e7

Please sign in to comment.