├── .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 |
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 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_java.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
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 |
--------------------------------------------------------------------------------