Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Connect SDK] Integrate with backend calls for client secret #9287

Merged

Conversation

simond-stripe
Copy link
Collaborator

@simond-stripe simond-stripe commented Sep 16, 2024

Summary

Adds networking to the example backend (https://stripe-connect-mobile-example-v1.glitch.me/) for getting the publishable key, accounts, and client secret for the SDK.

Motivation

Demonstrates a canonical integration of the ConnectSDK.

Testing

  • Added tests
  • Modified tests
  • Manually verified

Screenshots

UI

screen-1729231585
demo-1729231634.mp4

Network call logging

Screenshot 2024-10-18 at 2 06 50 AM

Copy link
Contributor

Risky Change

This is considered a risky change because it adjusts the sample app build.gradle, please review carefully.
We've seen issues in the past which resulted in failed builds for merchants. Please make sure the build.gradle change is intended.

By adding the label accept-risky-change to this PR, I acknowledge that I'm changing an example app and have verified that the SDK remains in a shippable state.

@simond-stripe simond-stripe changed the title Integrate with backend calls for client secret [Connect SDK] Integrate with backend calls for client secret Sep 16, 2024
@simond-stripe simond-stripe added the accept-risky-change accept-risky-change label Sep 24, 2024
@simond-stripe simond-stripe force-pushed the simond/connect-sdk-example-app-backend-integration branch from 5b9f620 to 132cadd Compare September 24, 2024 18:10
Copy link
Contributor

github-actions bot commented Sep 24, 2024

Diffuse output:

OLD: identity-example-release-base.apk (signature: V1, V2)
NEW: identity-example-release-pr.apk (signature: V1, V2)

          │          compressed          │         uncompressed         
          ├───────────┬───────────┬──────┼───────────┬───────────┬──────
 APK      │ old       │ new       │ diff │ old       │ new       │ diff 
──────────┼───────────┼───────────┼──────┼───────────┼───────────┼──────
      dex │     2 MiB │     2 MiB │  0 B │   4.1 MiB │   4.1 MiB │  0 B 
     arsc │     1 MiB │     1 MiB │  0 B │     1 MiB │     1 MiB │  0 B 
 manifest │   2.3 KiB │   2.3 KiB │  0 B │     8 KiB │     8 KiB │  0 B 
      res │ 301.8 KiB │ 301.8 KiB │  0 B │ 455.5 KiB │ 455.5 KiB │  0 B 
   native │   6.2 MiB │   6.2 MiB │  0 B │  15.8 MiB │  15.8 MiB │  0 B 
    asset │     7 KiB │     7 KiB │  0 B │   6.8 KiB │   6.8 KiB │  0 B 
    other │  85.5 KiB │  85.5 KiB │ -2 B │ 158.7 KiB │ 158.7 KiB │  0 B 
──────────┼───────────┼───────────┼──────┼───────────┼───────────┼──────
    total │   9.6 MiB │   9.6 MiB │ -2 B │  21.5 MiB │  21.5 MiB │  0 B 

 DEX     │ old   │ new   │ diff      
─────────┼───────┼───────┼───────────
   files │     1 │     1 │ 0         
 strings │ 20108 │ 20108 │ 0 (+0 -0) 
   types │  6205 │  6205 │ 0 (+0 -0) 
 classes │  4991 │  4991 │ 0 (+0 -0) 
 methods │ 30124 │ 30124 │ 0 (+0 -0) 
  fields │ 17572 │ 17572 │ 0 (+0 -0) 

 ARSC    │ old  │ new  │ diff 
─────────┼──────┼──────┼──────
 configs │  164 │  164 │  0   
 entries │ 3624 │ 3624 │  0
APK
   compressed    │  uncompressed   │                     
──────────┬──────┼──────────┬──────┤                     
 size     │ diff │ size     │ diff │ path                
──────────┼──────┼──────────┼──────┼─────────────────────
 28.3 KiB │ -3 B │ 62.6 KiB │  0 B │ ∆ META-INF/CERT.SF  
  1.2 KiB │ +1 B │  1.2 KiB │  0 B │ ∆ META-INF/CERT.RSA 
──────────┼──────┼──────────┼──────┼─────────────────────
 29.5 KiB │ -2 B │ 63.8 KiB │  0 B │ (total)

@simond-stripe simond-stripe force-pushed the simond/connect-sdk-example-app-backend-integration branch from 132cadd to d6fd4aa Compare September 24, 2024 18:42
@simond-stripe simond-stripe force-pushed the simond/connect-sdk-example-app-backend-integration branch from d6fd4aa to 6c7f034 Compare September 24, 2024 19:11
@simond-stripe simond-stripe marked this pull request as ready for review September 27, 2024 18:09
@simond-stripe simond-stripe requested review from a team as code owners September 27, 2024 18:09
Base automatically changed from simond/connect-sdk-example-app to master October 7, 2024 19:15
# Conflicts:
#	dependencies.gradle
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt
@simond-stripe simond-stripe force-pushed the simond/connect-sdk-example-app-backend-integration branch from 6c7f034 to 1422da5 Compare October 8, 2024 03:36
@@ -70,6 +70,7 @@ ext.versions = [
tensorflowLite : '2.11.0',
tensorflowLiteSupport : '0.4.3',
testParameterInjector : '1.17',
timber : '5.0.1',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a Logger class in stripe-core. Would this fit your needs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this looks great! My goal is to demonstrate reasonable logging behavior in our example app - I've updated the PR to remove Timber.

Copy link
Contributor

@lng-stripe lng-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is coming along nicely!

Approving for now as I know this is in very active development and I don't want to slow momentum. However, I have medium-high FUD around the EmbeddedComponentManager API.


@Preview(showBackground = true)
@Composable
fun LaunchEmbeddedComponentsScreenPreviewWithSelectedAccount() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make previews private here and below?

Suggested change
fun LaunchEmbeddedComponentsScreenPreviewWithSelectedAccount() {
private fun LaunchEmbeddedComponentsScreenPreviewWithSelectedAccount() {

}

object UserAgentHeader : FoldableRequestInterceptor {
private fun getUserAgent(): String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could be a val

val deserializer = object : Deserializable<T> {

override fun deserialize(response: Response): T {
println(response.toString())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

fun LaunchEmbeddedComponentsScreen(
embeddedComponentName: String,
selectedAccount: Merchant?,
connectSDKAccounts: List<Merchant>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: Not that performance is a concern, but if it's easy we should enable strong skipping mode to avoid recompositions with list params in composables (plus all the other situations)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. If I can apply this to just the connect module, I'll do that

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AccountSelector(
selectedAccount: Merchant? = null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
selectedAccount: Merchant? = null,
selectedAccount: Merchant?,

if (sdkPublishableKey != null && accounts != null) {
val embeddedComponentManager = remember(sdkPublishableKey) {
EmbeddedComponentManager(
activity = this@AccountOnboardingExampleActivity,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does EmbeddedComponentManager really need to keep an instance of Activity? Can we pass in the activity in present* method calls instead? Currently,

  1. This is a memory leak foot gun for users if they don't properly cleanup the manager when the Activity is destroyed.
  2. There's a disconnect in having both activity and fetchClientSecret as dependencies. In which architectural layer does this class belong? What if we want to cache and share the client secret between managers?
  3. This API prevents users from making this a singleton in their apps, and introduces a lot of friction in setting up DI.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are great points. This API is changing after review - my follow-up PR will make this a singleton and I believe should resolve most of these concerns, but let me know if you still have FUD after the next PR

constructor(
@Suppress("UNUSED_PARAMETER") activity: ComponentActivity,
@Suppress("UNUSED_PARAMETER") configuration: Configuration,
@Suppress("UNUSED_PARAMETER") fetchClientSecret: FetchClientSecretCallback,
) : this() {
throw NotImplementedError("Not yet implemented")
// TODO MXMOBILE-2760 - replace with actual implementation and remove the @Suppress annotations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove the other throws as well replace them with toasts instead. It was unclear to me as I was testing this when a crash was intentional versus not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. This should be easy to do while in development.

import com.stripe.android.connectsdk.example.networking.Merchant

@Composable
fun LaunchEmbeddedComponentsScreen(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was an Effect based on verb-like naming. Should change it to something like:

Suggested change
fun LaunchEmbeddedComponentsScreen(
fun EmbeddedComponentsLauncherScreen(

Copy link
Collaborator Author

@simond-stripe simond-stripe Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. This may change in an upcoming PR due to API revisions anyways, and either way I like the name better!

}

@Serializable
data class FetchClientSecretResponse(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: IMO we should prefer having only one public class per file. It makes finding things a lot easier.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I'll refactor in a follow-up

val state: StateFlow<PayoutsExampleState> = _state.asStateFlow()

init {
getAccounts()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll be adding retrying later?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my goal. It's not strictly necessary for this example app, but I think having a strong canonical example is useful

@simond-stripe
Copy link
Collaborator Author

@lng thanks for the thorough feedback! This isn't live yet and there's a number of PRs queued up behind this one, so I'll address this PR in a follow-up PR later today.

@simond-stripe simond-stripe merged commit cb70b1c into master Oct 18, 2024
15 checks passed
@simond-stripe simond-stripe deleted the simond/connect-sdk-example-app-backend-integration branch October 18, 2024 15:56
simond-stripe added a commit that referenced this pull request Oct 18, 2024
amk-stripe pushed a commit that referenced this pull request Oct 22, 2024
* Integrate with backend calls for client secret

# Conflicts:
#	dependencies.gradle
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/networking/EmbeddedComponentService.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleActivity.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/accountonboarding/AccountOnboardingExampleViewModel.kt
#	stripe-connect-example/src/main/java/com/stripe/android/connectsdk/example/ui/payouts/PayoutsExampleViewModel.kt

* Fix lint

* add dependencies file

* Move from timber to Logger

* Remove unnecessary import

* fix lint for deps

* Fix deps

* Fix colors, fix merge confligt

* Fix icon lint
simond-stripe added a commit that referenced this pull request Nov 6, 2024
* Rename stripe-connect -> connect

* Rename stripe-connect-example -> connect-example

* Update API - fragments, Appearance, and secret callback

* Move to stringRes

* PR feedback from #9287

* Refactor connectsdk to just connect for package

* Remove StrongSkippingMode for now (syntax is wrong)

* Update example artifact to connect from connectsdk

* Add placeholder Fragment UI

* update deps

* Remove unneeded function

* Remove unneeded import

* ... -> …

* Remove unneeded Manifest entry

* Rename stripe-connect.api to connect.api

* Restrict library group

* Add API

* Update dependency
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accept-risky-change accept-risky-change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants