69
loading...
This website collects cookies to deliver better user experience
expo init expo-plaid-sdk-integration -t expo-template-blank-typescript
yarn add react-native-plaid-link-sdk
App.tsx
to:import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { PlaidLink, LinkSuccess, LinkExit } from 'react-native-plaid-link-sdk'
export default function App() {
return (
<View style={styles.container}>
<PlaidLink
tokenConfig={{ token: '#GENERATED_LINK_TOKEN#', noLoadingState: false }}
onSuccess={(success: LinkSuccess) => console.log(success)}
onExit={(exit: LinkExit) => console.log(exit)}
>
<Text>Add Account</Text>
</PlaidLink>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
})
app.json
:"expo": {
...otherProps,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.expo.plaid"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"package": "com.expo.plaid"
}
}
TypeError: null is not an object (evaluating '_reactNative.NativeModules.RNLinksdk.continueFromRedirectUriString')
expo run
commands locally or using EAS build process. By building the dev client we will have a custom Expo Go which will add the Plaid library to its bundle, meaning you can use this client until you decide to add again something new that is not supported by it. For simplicity we will stay with the local run
commands. Then we just need to follow the Plaid readme setup guide for both iOS and Android.ios/Podfile
following string pod 'Plaid', '~> <insert latest version>
to pin the latest version, but, in reality, this is optional and we can easily work with the version currently bundled in the library. As a result, the only step we have to do is to initiate the expo-dev-client
by running:expo run:ios
Add Account
and you should see Plaid error complaining about the token we provided - but about that later.Unexpected environment string value: (null). Expected one of: production, sandbox, or development.
expo run:android
and press Add Account
at this stage, you will get an unhandled promise rejection..TypeError: null is not an object (evaluating '_reactNative.NativeModules.PlaidAndroid.startLinkActivityForResult')
API
page - Allowed Android Package
. You should configure there the Android package name from app.json
- com.expo.plaid
.Add import com.plaid.PlaidPackage; to the imports section
Add packages.add(new PlaidPackage()); to List<ReactPackage> getPackages();
withAndroidPlaid.ts
file and start transpiling it to javascript with this command:yarn tsc withAndroidPlaid.ts --watch --skipLibCheck
app.json
as a plugin:{
"expo": {
...otherProps,
"plugins": ["./withAndroidPlaid"]
}
}
withAndroidPlaid.ts
content to following:import type { ConfigPlugin } from '@expo/config-plugins'
import { withMainApplication } from '@expo/config-plugins'
function applyPackage(mainApplication: string) {
const plaidPackageImport = `import com.plaid.PlaidPackage;\n`
const plaidAddPackage = `packages.add(new PlaidPackage());`
// Make sure the project does not have the settings already
if (!mainApplication.includes(plaidPackageImport)) {
mainApplication = mainApplication.replace(
/package com.expo.plaid;/,
`package com.expo.plaid;\n${plaidPackageImport}`
)
}
if (!mainApplication.includes(plaidAddPackage)) {
mainApplication = mainApplication.replace(
/return packages;/,
`
${plaidAddPackage}
return packages;
`
)
}
return mainApplication
}
const withAndroidPlaid: ConfigPlugin = (expoConfig) => {
expoConfig = withMainApplication(expoConfig, (config) => {
config.modResults.contents = applyPackage(config.modResults.contents)
return config
})
return expoConfig
}
export default withAndroidPlaid
withMainApplication
, a mod provided by Expo allowing us to read and modify the content of MainApplication.java
. We provide the content to our function applyPackage
where we execute 2 string replacements to insert plaidPackageImport
and plaidAddPackage
constants into the file - the changes Plaid readme wanted from us.Our strategy is to simply find a stable part of the file where we can append our changes. Due to the string replacement nature, it is quite dangerous thing to rely on, because they could change with consequent React Native and Expo updates - so be sure these replacements still work when you upgrade.
expo prebuild -p android
you should now see updated MainApplication.java
. If you did something incorrectly, you may want to discard changes, check your plugin code, and try prebuild
again.dependencies {
// ...
implementation project(':react-native-plaid-link-sdk')
}
withAppBuildGradle
modifying the file within withAndroidPlaid
function.// ...
expoConfig = withAppBuildGradle(expoConfig, (config) => {
config.modResults.contents = applyImplementation(config.modResults.contents)
return config
})
// ...
applyImplementation
is our custom function following the previous strategy of appending plaidImplementation
string to the right place of the file.function applyImplementation(appBuildGradle: string) {
const plaidImplementation = `implementation project(':react-native-plaid-link-sdk')`
// Make sure the project does not have the dependency already
if (!appBuildGradle.includes(plaidImplementation)) {
return appBuildGradle.replace(
/dependencies\s?{/,
`dependencies {
${plaidImplementation}`
)
}
return appBuildGradle
}
settings.gradle
:include ':react-native-plaid-link-sdk'
project(':react-native-plaid-link-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-plaid-link-sdk/android')
withSettingsGradle
Expo mod:expoConfig = withSettingsGradle(expoConfig, (config) => {
config.modResults.contents = applySettings(config.modResults.contents)
return config
})
applySettings
function. Notice that we are just concatenating the strings with plus
symbol given that we don't really care about the exact placement of plaidSettings
constant.function applySettings(gradleSettings: string) {
const plaidSettings = `include ':react-native-plaid-link-sdk'
project(':react-native-plaid-link-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-plaid-link-sdk/android')`
// Make sure the project does not have the settings already
if (!gradleSettings.includes(`include ':react-native-plaid-link-sdk'`)) {
return gradleSettings + plaidSettings
}
return gradleSettings
}
If you lost track of the changes or applied them incorrectly, you can always go to the solution branch of this github repository for my final implementation.
Troubleshooting: I have discovered 2 potential issues when implementing Plaid on Android, so if you are facing build errors or your app is crashing, you might find an answer in these github issues: Kotlin version and OkHttp version.
expo run:android
to build the app with all modifications.Add Account
and you should see a different Plaid error complaining about configuration - but it is actually about the fake token we have provided.null - unable to open link, please check that your configuration is valid
App.tsx
. Normally you would get it from your backend, but for testing purposes we can actually use a very handy Postman collection provided by Plaid.client_id
and secret
from Plaid dashboard, you can hit https://sandbox.plaid.com/link/token/create
API endpoint and use the returned link_token
.{
"expiration": "2021-12-25T19:49:22Z",
"link_token": "link-sandbox-965dbc89-14fc-4122-b900-27a562de6db0",
"request_id": "AEBgG6EbWGsQ9aR"
}
Add Account
should finally open Plaid interface: