├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE ├── README.md ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── plaid │ │ └── linksample │ │ ├── LinkSampleApplication.kt │ │ ├── LinkSampleApplicationJava.java │ │ ├── MainActivity.kt │ │ ├── MainActivityJava.java │ │ ├── MainActivityStartActivityForResult.kt │ │ ├── MainActivityStartActivityForResultJava.java │ │ └── network │ │ ├── LinkSampleApi.kt │ │ └── LinkTokenRequester.kt │ └── res │ ├── drawable │ ├── add.xml │ └── plaid_icon.png │ ├── font │ ├── vaud.otf │ └── vaud_semibold.otf │ ├── layout │ ├── activity_main.xml │ └── activity_main_fragment.xml │ ├── menu │ ├── menu.xml │ └── menu_java.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── docs ├── link_demo.gif └── sdk-vs-webview-comparison.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── start_server.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # The problem 11 | 12 | Briefly describe the issue you are experiencing (or the feature you want to see added to the Plaid Link 13 | React Native SDK). Tell us what you were trying to do and what happened instead. 14 | 15 | # Environment 16 | 17 | | | | 18 | | ------------------------| ---------- | 19 | | Android OS Version | e.g. 5.0.0 (21) | 20 | | Android Devices/Emulators | e.g. Pixel 3a physical | 21 | 22 | # Steps to Reproduce 23 | 24 | If necessary, describe the problem you have been experiencing in more detail. 25 | Please include the configuration you are using for Link (exluding your keys 26 | and personally identifiable information) 27 | 28 | For example: 29 | ``` 30 | { 31 | "client_id":"OMITTED", 32 | "secret":"OMITTED", 33 | "user":{ 34 | "client_user_id":"OMITTED", 35 | "legal_name":"OMITTED" 36 | }, 37 | "client_name":"My application", 38 | "products":[ 39 | "auth" 40 | ], 41 | "country_codes":[ 42 | "US" 43 | ], 44 | "language":"en", 45 | "android_package_name":"com.mycompany.myapp" 46 | } 47 | ``` 48 | 49 | # Expected Result 50 | What did you expect to happen? 51 | 52 | # Screenshots 53 | If this is a visual bug a screenshot would be helpful. 54 | 55 | # Logs 56 | Any relevant logs from Android Logcat or the iOS console including stacktraces. 57 | 58 | # Code To Reproduce Issue 59 | With sample code it's easier to reproduce the bug and it's much faster to fix it. 60 | Don't forget to omit any keys or personally identifiable information. 61 | Please provide one of the following: 62 | 63 | 1. (Best) A link to a minimal demo app showing the faulty behaviour (a modified version of the sample app would be a great start) 64 | 1. (Better) A concise code sample which can be dropped into fresh application 65 | 1. A snippet of code for your configuration for opening Link 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/ 38 | .idea/workspace.xml 39 | .idea/tasks.xml 40 | .idea/gradle.xml 41 | .idea/assetWizardSettings.xml 42 | .idea/dictionaries 43 | .idea/libraries 44 | .idea/caches 45 | 46 | # Keystore files 47 | # Uncomment the following line if you do not want to check your keystore files in. 48 | #*.jks 49 | 50 | # External native build folder generated in Android Studio 2.2 and later 51 | .externalNativeBuild 52 | 53 | # Google Services (e.g. APIs or Firebase) 54 | google-services.json 55 | 56 | # Freeline 57 | freeline.py 58 | freeline/ 59 | freeline_project_description.json 60 | 61 | # fastlane 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | fastlane/readme.md 67 | 68 | # Node modules in server code 69 | server/ 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Plaid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plaid Link Sample Android App [![version][link-sdk-version]][link-sdk-url] 2 | This sample app will show you how Link Android SDK can integrate with your own app in both Kotlin and Java. Check out [the benefits](./docs/sdk-vs-webview-comparison.md) of using the SDK. 3 | 4 | 5 |

6 | Link demo gif 7 |

8 | 9 | > Detailed instructions on how to integrate with Plaid Link for Android in your app can be found in our [main documentation][link-android-docs]. 10 | 11 | 12 | # Getting Started 13 | To run the sample app, you'll need a Plaid account. You can create one on [our website][plaid-signup]. 14 | 15 | ## 1. Register your app id 16 | 1. Log into your [Plaid Dashboard][plaid-dashboard-api] at the API page 17 | 2. Next to "Allowed Android package names" click "Configure" then "Add New Android Package Name" 18 | 3. Enter the sample app package name: `com.plaid.linksample` 19 | 4. Click "Save Changes", you may be prompted to re-enter your password 20 | 21 | ## 2a. Generate a link_token and add it to the sample app 22 | 1. Clone the sample repository 23 | 2. Curl [/link/token/create](https://plaid.com/docs/#create-link-token) to create a new link_token 24 | 3. Copy and paste the link_token into the [kotlin][get-link-token-kotlin] or [java][get-link-token-java] LinkTokenRequester's `getToken()` function. 25 | 26 | OR 27 | 28 | ## 2b. Run the token server (imitation [backend server][link-quickstart]) 29 | 1. [Install npm][npm-installation] 30 | 2. Copy your client id and secret from your [Plaid Dashboard][plaid-dashboard-keys] keys page 31 | 3. Run `./start_server.sh ${CLIENT_ID} ${SECRET}` but replace `client_id` and `secret` with values from your dashboard account. 32 | 4. Server is now running on `localhost:8000` 33 | 34 | ## 3. Run the sample application 35 | 1. 🚀 36 | 37 | # Features 38 | - How to integrate the Plaid Link sdk: `build.gradle` files, `link_token` configuration, `Plaid` initialization 39 | - Kotlin and Java sample Activity that show how to start Link and receive a result 40 | - Use of `OpenPlaidLink` `ActivityResultContract` for easy handling of Link results 41 | - _Optional_ use of `LinkEventListener` to get events from Link 42 | 43 | Have a look at our [main documentation][link-android-docs] for all Plaid Link SDK features. 44 | 45 | # Releases 46 | Our [change log][changelog] has release history. 47 | 48 | We create release candidates (e.g. 3.2.0-rc1) as beta previews for developers. These are helpful for customers who either are 1. waiting for a specific fix or 2. extremely eager for specific features. They do not hold the same quality guarantee as our official releases, and should NOT be used in production. The official releases come ~2 weeks after the first release candidate (rc1). 49 | 50 | The latest version of Plaid Link is [![version][link-sdk-version]][link-sdk-url]. 51 | 52 | ```kotlin 53 | implementation("com.plaid.link:sdk-core:") 54 | ``` 55 | 56 | R8 and ProGuard rules are already bundled in our AAR and will be used automatically. 57 | 58 | ## Upgrading 59 | 60 | Plaid releases updates to the SDK approximately every few months. For the best user experience, we recommend using the latest version of the SDK. 61 | 62 | Major SDK versions are released annually. SDK versions are supported for two years; with each major SDK release, Plaid will stop officially supporting any previous SDK versions that are more than two years old. 63 | 64 | While these older versions are expected to continue to work without disruption, Plaid will not provide assistance with unsupported SDK versions. 65 | 66 | # Migration Guide 67 | 68 | ### Changes from SDK 3.x to 4.0 69 | 70 | #### 1. Authentication Method Changes 71 | **BREAKING**: Removed deprecated support for public key authentication. 72 | 73 | If your integration is using public key authentication, it's essential to migrate to Link Tokens. This change does not affect you if you've already made this transition. For detailed instructions, refer to Plaid's [migration guide](https://plaid.com/docs/link-token-migration-guide). 74 | 75 | #### 2. Open Options Configuration 76 | **BREAKING**: Removed `extraParams(extraParams: Map)` setter method from `LinkTokenConfiguration#Builder`. 77 | 78 | If your integration relies on `extraParams`, you must now configure these parameters while creating your [Link Tokens](https://plaid.com/docs/api/tokens/). Update your implementation accordingly. 79 | 80 | ### 3. Upgrade to Kotlin 1.8 81 | The Link Android SDK version of Kotlin has been upgraded to 1.8 and may need to be updated in your project. 82 | 83 | # License 84 | ``` 85 | MIT License 86 | 87 | Copyright (c) 2020 Plaid 88 | 89 | Permission is hereby granted, free of charge, to any person obtaining a copy 90 | of this software and associated documentation files (the "Software"), to deal 91 | in the Software without restriction, including without limitation the rights 92 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 93 | copies of the Software, and to permit persons to whom the Software is 94 | furnished to do so, subject to the following conditions: 95 | 96 | The above copyright notice and this permission notice shall be included in all 97 | copies or substantial portions of the Software. 98 | 99 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 100 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 101 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 102 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 103 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 104 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 105 | SOFTWARE. 106 | ``` 107 | 108 | 109 | [link-sdk-version]: https://img.shields.io/maven-central/v/com.plaid.link/sdk-core 110 | [link-sdk-url]: https://search.maven.org/artifact/com.plaid.link/sdk-core 111 | [link-android-docs]: https://plaid.com/docs/link/android/ 112 | [plaid-signup]: https://dashboard.plaid.com/signup?email= 113 | [plaid-dashboard-api]: https://dashboard.plaid.com/team/api 114 | [plaid-dashboard-keys]: https://dashboard.plaid.com/team/keys 115 | [changelog]: https://github.com/plaid/plaid-link-android/releases 116 | [get-link-token-kotlin]: app/src/main/java/com/plaid/linksample/MainActivity.kt 117 | [get-link-token-java]: app/src/main/java/com/plaid/linksample/MainActivityJava.java 118 | [npm-installation]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm 119 | [link-quickstart]: https://plaid.com/docs/quickstart/ 120 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | apply plugin: 'com.android.application' 6 | apply plugin: 'kotlin-android' 7 | 8 | android { 9 | defaultConfig { 10 | applicationId "com.plaid.linksample" 11 | minSdkVersion 21 12 | targetSdkVersion 34 13 | compileSdk 34 14 | versionCode 1 15 | versionName "1.0" 16 | } 17 | 18 | compileOptions { 19 | sourceCompatibility JavaVersion.VERSION_17 20 | targetCompatibility JavaVersion.VERSION_17 21 | } 22 | namespace 'com.plaid.linksample' 23 | } 24 | 25 | dependencies { 26 | implementation "com.plaid.link:sdk-core:5.1.0" 27 | 28 | implementation "androidx.appcompat:appcompat:1.6.1" 29 | implementation "androidx.core:core-ktx:1.12.0" 30 | implementation "androidx.constraintlayout:constraintlayout:2.1.4" 31 | implementation "com.google.android.material:material:1.10.0" 32 | implementation "io.reactivex.rxjava3:rxandroid:3.0.0" 33 | implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' 34 | 35 | implementation "com.squareup.retrofit2:retrofit:2.9.0" 36 | implementation "com.squareup.retrofit2:converter-gson:2.9.0" 37 | implementation "com.google.code.gson:gson:2.10.1" 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 41 | 42 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/LinkSampleApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample 6 | 7 | import android.app.Application 8 | import com.plaid.link.Plaid 9 | 10 | @Suppress("Unused") 11 | class LinkSampleApplication : Application() { 12 | 13 | override fun onCreate() { 14 | super.onCreate() 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/LinkSampleApplicationJava.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample; 6 | 7 | import android.app.Application; 8 | 9 | import com.plaid.link.Plaid; 10 | 11 | @SuppressWarnings("unused") 12 | public class LinkSampleApplicationJava extends Application { 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample 6 | 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import android.util.Log 10 | import android.view.Menu 11 | import android.view.MenuItem 12 | import android.widget.TextView 13 | import android.widget.Toast 14 | import androidx.appcompat.app.AppCompatActivity 15 | import com.google.android.material.button.MaterialButton 16 | import com.plaid.link.FastOpenPlaidLink 17 | import com.plaid.link.Plaid 18 | import com.plaid.link.PlaidHandler 19 | import com.plaid.link.configuration.LinkTokenConfiguration 20 | import com.plaid.link.result.LinkExit 21 | import com.plaid.link.result.LinkSuccess 22 | import com.plaid.linksample.network.LinkTokenRequester 23 | 24 | class MainActivity : AppCompatActivity() { 25 | 26 | private lateinit var result: TextView 27 | private lateinit var tokenResult: TextView 28 | private lateinit var prepareButton: MaterialButton 29 | private lateinit var openButton: MaterialButton 30 | private var plaidHandler: PlaidHandler? = null 31 | 32 | private val linkAccountToPlaid = registerForActivityResult(FastOpenPlaidLink()) { result -> 33 | when (result) { 34 | is LinkSuccess -> showSuccess(result) 35 | is LinkExit -> showFailure(result) 36 | } 37 | } 38 | 39 | override fun onCreate(savedInstanceState: Bundle?) { 40 | super.onCreate(savedInstanceState) 41 | setContentView(R.layout.activity_main) 42 | result = findViewById(R.id.result) 43 | tokenResult = findViewById(R.id.public_token_result) 44 | 45 | prepareButton = findViewById(R.id.prepare_link) 46 | prepareButton.setOnClickListener { 47 | setOptionalEventListener() 48 | prepareLink() 49 | } 50 | 51 | openButton = findViewById(R.id.open_link) 52 | openButton.setOnClickListener { 53 | openLink() 54 | } 55 | } 56 | 57 | private fun prepareLink() { 58 | LinkTokenRequester.token.subscribe(::onLinkTokenSuccess, ::onLinkTokenError) 59 | } 60 | 61 | /** 62 | * Optional, set an [event listener](https://plaid.com/docs/link/android/#handling-onevent). 63 | */ 64 | private fun setOptionalEventListener() = Plaid.setLinkEventListener { event -> 65 | Log.i("Event", event.toString()) 66 | } 67 | 68 | /** 69 | * For all Link configuration options, have a look at the 70 | * [parameter reference](https://plaid.com/docs/link/android/#parameter-reference). 71 | */ 72 | private fun openLink() { 73 | prepareButton.isEnabled = true 74 | openButton.isEnabled = false 75 | plaidHandler?.let { linkAccountToPlaid.launch(it) } 76 | } 77 | 78 | private fun onLinkTokenSuccess(linkToken: String) { 79 | prepareButton.isEnabled = false 80 | openButton.isEnabled = true 81 | val tokenConfiguration = LinkTokenConfiguration.Builder() 82 | .token(linkToken) 83 | .build() 84 | plaidHandler = Plaid.create(this.application, tokenConfiguration) 85 | } 86 | 87 | private fun onLinkTokenError(error: Throwable) { 88 | if (error is java.net.ConnectException) { 89 | Toast.makeText(this, "Please run `sh start_server.sh `", Toast.LENGTH_LONG).show() 90 | return 91 | } 92 | Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() 93 | } 94 | 95 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 96 | menuInflater.inflate(R.menu.menu, menu) 97 | return true 98 | } 99 | 100 | override fun onOptionsItemSelected(item: MenuItem): Boolean = 101 | when (item.itemId) { 102 | R.id.show_java -> { 103 | val intent = Intent(this@MainActivity, MainActivityJava::class.java) 104 | intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK 105 | startActivity(intent) 106 | true 107 | } 108 | R.id.show_activity_result -> { 109 | val intent = Intent(this@MainActivity, MainActivityStartActivityForResult::class.java) 110 | intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK 111 | startActivity(intent) 112 | true 113 | } 114 | R.id.show_activity_result_java -> { 115 | val intent = Intent(this@MainActivity, MainActivityStartActivityForResultJava::class.java) 116 | intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK 117 | startActivity(intent) 118 | true 119 | } 120 | else -> super.onOptionsItemSelected(item) 121 | } 122 | 123 | private fun showSuccess(success: LinkSuccess) { 124 | tokenResult.text = getString(R.string.public_token_result, success.publicToken) 125 | result.text = getString(R.string.content_success) 126 | } 127 | 128 | private fun showFailure(exit: LinkExit) { 129 | tokenResult.text = "" 130 | if (exit.error != null) { 131 | result.text = getString(R.string.content_exit, exit.error?.displayMessage, exit.error?.errorCode) 132 | } else { 133 | result.text = getString(R.string.content_cancel, exit.metadata.status?.jsonValue ?: "unknown") 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/MainActivityJava.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample; 6 | 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.Menu; 11 | import android.view.MenuInflater; 12 | import android.view.MenuItem; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | import androidx.activity.result.ActivityResultLauncher; 16 | import androidx.annotation.NonNull; 17 | import androidx.appcompat.app.AppCompatActivity; 18 | import com.google.android.material.button.MaterialButton; 19 | import com.plaid.link.FastOpenPlaidLink; 20 | import com.plaid.link.Plaid; 21 | import com.plaid.link.PlaidHandler; 22 | import com.plaid.link.configuration.LinkTokenConfiguration; 23 | import com.plaid.link.result.LinkExit; 24 | import com.plaid.link.result.LinkSuccess; 25 | import com.plaid.linksample.network.LinkTokenRequester; 26 | import kotlin.Unit; 27 | 28 | 29 | public class MainActivityJava extends AppCompatActivity { 30 | 31 | private TextView result; 32 | private TextView tokenResult; 33 | private MaterialButton prepareButton; 34 | private MaterialButton openButton; 35 | 36 | private PlaidHandler plaidHandler = null; 37 | 38 | private ActivityResultLauncher linkAccountToPlaid = registerForActivityResult( 39 | new FastOpenPlaidLink(), 40 | result -> { 41 | if (result instanceof LinkSuccess) { 42 | showSuccess((LinkSuccess) result); 43 | } else { 44 | showFailure((LinkExit) result); 45 | } 46 | }); 47 | 48 | private void showSuccess(LinkSuccess success) { 49 | tokenResult.setText(getString(R.string.public_token_result, success.getPublicToken())); 50 | result.setText(getString(R.string.content_success)); 51 | } 52 | 53 | private void showFailure(LinkExit exit) { 54 | tokenResult.setText(""); 55 | if (exit.getError() != null) { 56 | result.setText(getString( 57 | R.string.content_exit, 58 | exit.getError().getDisplayMessage(), 59 | exit.getError().getErrorCode())); 60 | } else { 61 | result.setText(getString( 62 | R.string.content_cancel, 63 | exit.getMetadata().getStatus() != null ? exit.getMetadata().getStatus().getJsonValue() : "unknown")); 64 | } 65 | } 66 | 67 | @Override 68 | protected void onCreate(Bundle savedInstanceState) { 69 | super.onCreate(savedInstanceState); 70 | setContentView(R.layout.activity_main); 71 | result = findViewById(R.id.result); 72 | tokenResult = findViewById(R.id.public_token_result); 73 | 74 | prepareButton = findViewById(R.id.prepare_link); 75 | prepareButton.setOnClickListener(view -> { 76 | setOptionalEventListener(); 77 | prepareLink(); 78 | }); 79 | 80 | openButton = findViewById(R.id.open_link); 81 | openButton.setOnClickListener(view -> { 82 | openLink(); 83 | }); 84 | } 85 | 86 | private void prepareLink() { 87 | LinkTokenRequester.INSTANCE.getToken() 88 | .subscribe(this::onLinkTokenSuccess, this::onLinkTokenError); 89 | } 90 | 91 | /** 92 | * Optional, set an event listener. 93 | */ 94 | private void setOptionalEventListener() { 95 | Plaid.setLinkEventListener(linkEvent -> { 96 | Log.i("Event", linkEvent.toString()); 97 | return Unit.INSTANCE; 98 | }); 99 | } 100 | 101 | /** 102 | * For all Link configuration options, have a look at the 103 | * parameter reference 104 | */ 105 | private void openLink() { 106 | prepareButton.setEnabled(true); 107 | openButton.setEnabled(false); 108 | linkAccountToPlaid.launch(plaidHandler); 109 | } 110 | 111 | private void onLinkTokenSuccess(String token) { 112 | prepareButton.setEnabled(false); 113 | openButton.setEnabled(true); 114 | LinkTokenConfiguration configuration = new LinkTokenConfiguration.Builder() 115 | .token(token) 116 | .build(); 117 | plaidHandler = Plaid.create(this.getApplication(), configuration); 118 | } 119 | 120 | private void onLinkTokenError(Throwable error) { 121 | if (error instanceof java.net.ConnectException) { 122 | Toast.makeText( 123 | this, 124 | "Please run `sh start_server.sh `", 125 | Toast.LENGTH_LONG).show(); 126 | return; 127 | } 128 | Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show(); 129 | } 130 | 131 | @Override 132 | public boolean onCreateOptionsMenu(Menu menu) { 133 | MenuInflater inflater = getMenuInflater(); 134 | inflater.inflate(R.menu.menu_java, menu); 135 | return true; 136 | } 137 | 138 | @SuppressWarnings("SwitchStatementWithTooFewBranches") 139 | @Override 140 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 141 | switch (item.getItemId()) { 142 | case R.id.show_kotlin: 143 | Intent intent = new Intent(this, MainActivity.class); 144 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 145 | startActivity(intent); 146 | return true; 147 | default: 148 | return super.onOptionsItemSelected(item); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/MainActivityStartActivityForResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample 6 | 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import android.util.Log 10 | import android.view.View 11 | import android.widget.TextView 12 | import android.widget.Toast 13 | import androidx.appcompat.app.AppCompatActivity 14 | import com.google.android.material.button.MaterialButton 15 | import com.plaid.link.Plaid 16 | import com.plaid.link.PlaidHandler 17 | import com.plaid.link.configuration.LinkTokenConfiguration 18 | import com.plaid.link.result.LinkResultHandler 19 | import com.plaid.linksample.network.LinkTokenRequester 20 | 21 | /** 22 | * Old approach to opening Plaid Link, we recommend switching over to the 23 | * OpenPlaidLink ActivityResultContract instead. 24 | */ 25 | class MainActivityStartActivityForResult : AppCompatActivity() { 26 | 27 | private lateinit var result: TextView 28 | private lateinit var tokenResult: TextView 29 | private lateinit var prepareButton: MaterialButton 30 | private lateinit var openButton: MaterialButton 31 | private var plaidHandler: PlaidHandler? = null 32 | 33 | private val myPlaidResultHandler by lazy { 34 | LinkResultHandler( 35 | onSuccess = { 36 | tokenResult.text = getString(R.string.public_token_result, it.publicToken) 37 | result.text = getString(R.string.content_success) 38 | }, 39 | onExit = { 40 | tokenResult.text = "" 41 | if (it.error != null) { 42 | result.text = getString( 43 | R.string.content_exit, 44 | it.error?.displayMessage, 45 | it.error?.errorCode 46 | ) 47 | } else { 48 | result.text = getString( 49 | R.string.content_cancel, 50 | it.metadata.status?.jsonValue ?: "unknown" 51 | ) 52 | } 53 | } 54 | ) 55 | } 56 | 57 | override fun onCreate(savedInstanceState: Bundle?) { 58 | super.onCreate(savedInstanceState) 59 | setContentView(R.layout.activity_main) 60 | result = findViewById(R.id.result) 61 | tokenResult = findViewById(R.id.public_token_result) 62 | 63 | prepareButton = findViewById(R.id.prepare_link) 64 | prepareButton.setOnClickListener { 65 | setOptionalEventListener() 66 | prepareLink() 67 | } 68 | 69 | openButton = findViewById(R.id.open_link) 70 | openButton.setOnClickListener { 71 | setOptionalEventListener() 72 | openLink() 73 | } 74 | } 75 | 76 | private fun prepareLink() { 77 | LinkTokenRequester.token.subscribe(::onLinkTokenSuccess, ::onLinkTokenError) 78 | } 79 | /** 80 | * Optional, set an [event listener](https://plaid.com/docs/link/android/#handling-onevent). 81 | */ 82 | private fun setOptionalEventListener() = Plaid.setLinkEventListener { event -> 83 | Log.i("Event", event.toString()) 84 | } 85 | 86 | /** 87 | * For all Link configuration options, have a look at the 88 | * [parameter reference](https://plaid.com/docs/link/android/#parameter-reference). 89 | */ 90 | private fun openLink() { 91 | prepareButton.isEnabled = true 92 | openButton.isEnabled = false 93 | plaidHandler?.open(this) 94 | } 95 | 96 | private fun onLinkTokenSuccess(linkToken: String) { 97 | val tokenConfiguration = LinkTokenConfiguration.Builder() 98 | .token(linkToken) 99 | .build() 100 | plaidHandler = Plaid.create( 101 | this.application, 102 | tokenConfiguration 103 | ) 104 | prepareButton.isEnabled = false 105 | openButton.isEnabled = true 106 | } 107 | 108 | private fun onLinkTokenError(error: Throwable) { 109 | if (error is java.net.ConnectException) { 110 | Toast.makeText(this, "Please run `sh start_server.sh `", Toast.LENGTH_LONG).show() 111 | return 112 | } 113 | Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() 114 | } 115 | 116 | @Suppress("DEPRECATION") 117 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 118 | super.onActivityResult(requestCode, resultCode, intent) 119 | if (!myPlaidResultHandler.onActivityResult(requestCode, resultCode, data)) { 120 | Log.i(MainActivity::class.java.simpleName, "Not handled") 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/MainActivityStartActivityForResultJava.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | package com.plaid.linksample; 6 | 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.Menu; 11 | import android.view.MenuInflater; 12 | import android.view.MenuItem; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | import androidx.annotation.NonNull; 16 | import androidx.annotation.Nullable; 17 | import androidx.appcompat.app.AppCompatActivity; 18 | import com.google.android.material.button.MaterialButton; 19 | import com.plaid.link.Plaid; 20 | import com.plaid.link.PlaidHandler; 21 | import com.plaid.link.configuration.LinkTokenConfiguration; 22 | import com.plaid.link.result.LinkResultHandler; 23 | import com.plaid.linksample.network.LinkTokenRequester; 24 | import kotlin.Unit; 25 | 26 | /** 27 | * Old approach to opening Plaid Link, we recommend switching over to the 28 | * OpenPlaidLink ActivityResultContract instead. 29 | */ 30 | public class MainActivityStartActivityForResultJava extends AppCompatActivity { 31 | 32 | private TextView result; 33 | private TextView tokenResult; 34 | private MaterialButton prepareButton; 35 | private MaterialButton openButton; 36 | private PlaidHandler plaidHandler; 37 | 38 | private LinkResultHandler myPlaidResultHandler = new LinkResultHandler( 39 | linkSuccess -> { 40 | tokenResult.setText(getString( 41 | R.string.public_token_result, 42 | linkSuccess.getPublicToken())); 43 | result.setText(getString( 44 | R.string.content_success)); 45 | return Unit.INSTANCE; 46 | }, 47 | linkExit -> { 48 | tokenResult.setText(""); 49 | if (linkExit.getError() != null) { 50 | result.setText(getString( 51 | R.string.content_exit, 52 | linkExit.getError().getDisplayMessage(), 53 | linkExit.getError().getErrorCode())); 54 | } else { 55 | result.setText(getString( 56 | R.string.content_cancel, 57 | linkExit.getMetadata().getStatus() != null ? linkExit.getMetadata() 58 | .getStatus() 59 | .getJsonValue() : "unknown")); 60 | } 61 | return Unit.INSTANCE; 62 | } 63 | ); 64 | 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | setContentView(R.layout.activity_main); 69 | result = findViewById(R.id.result); 70 | tokenResult = findViewById(R.id.public_token_result); 71 | 72 | prepareButton = findViewById(R.id.prepare_link); 73 | prepareButton.setOnClickListener(view -> { 74 | setOptionalEventListener(); 75 | prepareLink(); 76 | }); 77 | 78 | openButton = findViewById(R.id.open_link); 79 | openButton.setOnClickListener(view -> { 80 | openLink(); 81 | }); 82 | } 83 | 84 | private void prepareLink() { 85 | LinkTokenRequester.INSTANCE.getToken() 86 | .subscribe(this::onLinkTokenSuccess, this::onLinkTokenError); 87 | } 88 | 89 | /** 90 | * Optional, set an event listener. 91 | */ 92 | private void setOptionalEventListener() { 93 | Plaid.setLinkEventListener(linkEvent -> { 94 | Log.i("Event", linkEvent.toString()); 95 | return Unit.INSTANCE; 96 | }); 97 | } 98 | 99 | /** 100 | * For all Link configuration options, have a look at the 101 | * parameter reference 102 | */ 103 | private void openLink() { 104 | prepareButton.setEnabled(true); 105 | openButton.setEnabled(false); 106 | plaidHandler.open(this); 107 | } 108 | 109 | private void onLinkTokenSuccess(String token) { 110 | prepareButton.setEnabled(false); 111 | openButton.setEnabled(true); 112 | plaidHandler = Plaid.create( 113 | getApplication(), 114 | new LinkTokenConfiguration.Builder() 115 | .token(token) 116 | .build()); 117 | } 118 | 119 | private void onLinkTokenError(Throwable error) { 120 | if (error instanceof java.net.ConnectException) { 121 | Toast.makeText( 122 | this, 123 | "Please run `sh start_server.sh `", 124 | Toast.LENGTH_LONG).show(); 125 | return; 126 | } 127 | Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show(); 128 | } 129 | 130 | @Override 131 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 132 | super.onActivityResult(requestCode, resultCode, data); 133 | if (!myPlaidResultHandler.onActivityResult(requestCode, resultCode, data)) { 134 | Log.i(MainActivityJava.class.getSimpleName(), "Not handled"); 135 | } 136 | } 137 | 138 | @Override 139 | public boolean onCreateOptionsMenu(Menu menu) { 140 | MenuInflater inflater = getMenuInflater(); 141 | inflater.inflate(R.menu.menu_java, menu); 142 | return true; 143 | } 144 | 145 | @SuppressWarnings("SwitchStatementWithTooFewBranches") 146 | @Override 147 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 148 | switch (item.getItemId()) { 149 | case R.id.show_kotlin: 150 | Intent intent = new Intent(this, MainActivity.class); 151 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 152 | startActivity(intent); 153 | return true; 154 | default: 155 | return super.onOptionsItemSelected(item); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/network/LinkSampleApi.kt: -------------------------------------------------------------------------------- 1 | package com.plaid.linksample.network 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import io.reactivex.rxjava3.core.Single 5 | import retrofit2.http.POST 6 | 7 | /** 8 | * API calls to our localhost token server. 9 | */ 10 | interface LinkSampleApi { 11 | 12 | @POST("/api/create_link_token") 13 | fun getLinkToken(): Single 14 | } 15 | 16 | data class LinkToken( 17 | @SerializedName("link_token") val link_token: String 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/plaid/linksample/network/LinkTokenRequester.kt: -------------------------------------------------------------------------------- 1 | package com.plaid.linksample.network 2 | 3 | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers 4 | import io.reactivex.rxjava3.schedulers.Schedulers 5 | import okhttp3.OkHttpClient 6 | import retrofit2.Retrofit 7 | import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory 8 | import retrofit2.converter.gson.GsonConverterFactory 9 | 10 | object LinkTokenRequester { 11 | // This value is setup to work with emulators. Modify this value to your PC's IP address if not. 12 | private val baseUrl = "http://10.0.2.2:8000" 13 | 14 | private val retrofit: Retrofit = Retrofit.Builder() 15 | .baseUrl(baseUrl) 16 | .client(OkHttpClient.Builder().build()) 17 | .addConverterFactory(GsonConverterFactory.create()) 18 | .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) 19 | .build() 20 | 21 | private val api = retrofit.create(LinkSampleApi::class.java) 22 | 23 | /** 24 | * In production, make an API request to your server to fetch 25 | * a new link_token. Learn more at https://plaid.com/docs/#create-link-token. 26 | * 27 | * You can optionally curl for a link_token instead of running the node-quickstart server, 28 | * and copy and paste the link_token value here. 29 | */ 30 | val token 31 | get() = api.getLinkToken() 32 | .subscribeOn(Schedulers.io()) 33 | .observeOn(AndroidSchedulers.mainThread()) 34 | .map { it.link_token } 35 | 36 | //Comment out the above and uncomment the below to use a curled Link Token 37 | //val token 38 | // get() = Single.just("") 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/add.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/plaid_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plaid/plaid-link-android/b31cd999167b188006427fe54096014cdeaa11f1/app/src/main/res/drawable/plaid_icon.png -------------------------------------------------------------------------------- /app/src/main/res/font/vaud.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plaid/plaid-link-android/b31cd999167b188006427fe54096014cdeaa11f1/app/src/main/res/font/vaud.otf -------------------------------------------------------------------------------- /app/src/main/res/font/vaud_semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plaid/plaid-link-android/b31cd999167b188006427fe54096014cdeaa11f1/app/src/main/res/font/vaud_semibold.otf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 21 | 22 | 31 | 32 | 39 | 40 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_fragment.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 23 | 24 | 32 | 33 | 43 | 44 | 51 | 52 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_java.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | #111111 7 | #111111 8 | #0A85EA 9 | #FFFFFF 10 | 11 | #4B4B4B 12 | #ffffff 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 16dp 7 | 8 | 16sp 9 | 24sp 10 | 11 | 20sp 12 | 24sp 13 | 14 | 16dp 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Link demo 7 | Link demo 8 | Link demo (java) 9 | public_token:\n%s 10 | 11 | You did it! See, that wasn\'t so hard :) 12 | 13 | \n\nThe next step is adding the Link Android SDK to your app. 14 | 15 | \n1) Send the public token shown above to your server to exchange it for an access token and get access to your data 16 | \n2) Visit http://plaid.com/docs/link/android for more information on how to integrate 17 | \n3) Ready for the big leagues? Unlock production access by visiting http://plaid.com/contact 18 | Institution Id:\n%1$s\n\n Institution Name:\n%2$s\n\n Link Session Id:\n%3$s\n\n Status:\n%4$s 19 | 20 | 21 | Uh-oh! It seems something went wrong:\n\"%1$s\" 22 | 23 | \n\nVisit https://plaid.com/docs/#errors for more information on the error code below 24 | \nError Code: %2$s 25 | 26 | You left Link without completing the flow. Reason: %1$s 27 | Exception Class:\n%1$s\n\n Exception Message:\n%2$s 28 | 29 | Welcome to the sample app. It will show you how Link Android SDK can integrate with your own app. We hope you’ll find that:\n 30 | \n\t• It’s easy to integrate, with fewer lines than webviews 31 | \n\t• It features enhanced security and a type-safe API 32 | \n\t• It supports all Link flows, including oauth 33 | \n\t• You’ll get monthly updates from Plaid 34 | \n\t• You can get support directly from the Plaid team 35 | 36 | Open Java demo 37 | Open Kotlin demo 38 | Prepare Link 39 | Open Link 40 | Open startActivityForResult demo (Kotlin) 41 | Link demo (startActivityForResult) 42 | Open startActivityForResult demo (Java) 43 | Link demo (startActivityForResult Java) 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 14 | 15 | 18 | 19 | 25 | 26 | 32 | 33 | 44 | 45 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 6 | 7 | buildscript { 8 | ext.kotlin_version = '1.8.22' 9 | repositories { 10 | google() 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | classpath 'com.android.tools.build:gradle:8.1.3' 16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | google() 25 | mavenCentral() 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /docs/link_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plaid/plaid-link-android/b31cd999167b188006427fe54096014cdeaa11f1/docs/link_demo.gif -------------------------------------------------------------------------------- /docs/sdk-vs-webview-comparison.md: -------------------------------------------------------------------------------- 1 | # Plaid SDK vs Webview 2 | Integrating with the SDK provides many benefits over using a [WebView](https://developer.android.com/reference/android/webkit/WebView). 3 | 4 | | | SDK | Webview | 5 | | :--- | :----: | :---: | 6 | | Lines of code to integrate | <20 | >100 | 7 | | Type-safe API | X | | 8 | | Support for all link flows (including OAuth!) | X | | 9 | | Monthly updates with the latest features | X | | 10 | | Support from Plaid | X | | 11 | | Up-to-date documentation | X | | 12 | 13 | 14 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2020 Plaid Technologies, Inc. 3 | # 4 | 5 | # Project-wide Gradle settings. 6 | # IDE (e.g. Android Studio) users: 7 | # Gradle settings configured through the IDE *will override* 8 | # any settings specified in this file. 9 | # For more details on how to configure your build environment visit 10 | # http://www.gradle.org/docs/current/userguide/build_environment.html 11 | # Specifies the JVM arguments used for the daemon process. 12 | # The setting is particularly useful for tweaking memory settings. 13 | org.gradle.jvmargs=-Xmx1536m 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | # AndroidX package structure to make it clearer which packages are bundled with the 19 | # Android operating system, and which are packaged with your app's APK 20 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 21 | android.useAndroidX=true 22 | # Automatically convert third-party libraries to use AndroidX 23 | android.enableJetifier=true 24 | # Kotlin code style for this project: "official" or "obsolete": 25 | kotlin.code.style=official 26 | 27 | org.gradle.parallel=true 28 | org.gradle.configureondemand=true 29 | android.defaults.buildfeatures.buildconfig=true 30 | android.nonTransitiveRClass=false 31 | android.nonFinalResIds=false 32 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plaid/plaid-link-android/b31cd999167b188006427fe54096014cdeaa11f1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 14 14:34:25 CEST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Plaid Technologies, Inc. 3 | */ 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /start_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir server 4 | cd server 5 | git clone https://github.com/plaid/quickstart.git 6 | cd quickstart/node 7 | npm install 8 | 9 | # Start the Quickstart with your API keys from the Dashboard 10 | # https://dashboard.plaid.com/account/keys 11 | # 12 | # PLAID_PRODUCTS is a comma-separated list of products to use when 13 | # initializing Link, see https://plaid.com/docs/#item-product-access 14 | # for complete list. 15 | 16 | # PLAID_COUNTRY_CODES is a comma-separated list of countries to use when 17 | # initializing Link, see plaid.com/docs/faq/#does-plaid-support-international-bank-accounts- 18 | # for a complete list 19 | 20 | if [ -z "$1" ] 21 | then 22 | echo "Client id must be supplied" 23 | fi 24 | 25 | if [ -z "$2" ] 26 | then 27 | echo "Client secret must be supplied" 28 | fi 29 | 30 | PLAID_CLIENT_ID=$1 \ 31 | PLAID_SECRET=$2 \ 32 | PLAID_ENV='sandbox' \ 33 | PLAID_PRODUCTS='transactions' \ 34 | PLAID_COUNTRY_CODES='US' \ 35 | PLAID_ANDROID_PACKAGE_NAME='com.plaid.linksample' \ 36 | node index.js 37 | 38 | # Go to http://localhost:8000 39 | --------------------------------------------------------------------------------