Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Objective-C example #23

Open
andreieuganox opened this issue Oct 26, 2020 · 7 comments
Open

Objective-C example #23

andreieuganox opened this issue Oct 26, 2020 · 7 comments

Comments

@andreieuganox
Copy link

Is there any pure Objective-C example anywhere? We use React Native, so to bridge it we need to be able to init the SDK from Obj-C...

@kasper-lahti
Copy link
Contributor

We don't have any Objective-C example at the moment but we'll take a look at what we can do to support using Tink Link with React Native.

@MartinInAction
Copy link

MartinInAction commented Mar 2, 2021

Hi! I made a simple bridge to open the tinkLinkSDK in react-native... Might be helpful!

//  TinkLinkManager.m
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(TinkLinkSDK, NSObject)

RCT_EXTERN_METHOD(startSDK: (NSString *)clientID
                  market:(NSString *)market
                  urlScheme:(NSString *)urlScheme
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject
                )


@end
//  TinkLinkManager.swift
import Foundation
import UIKit
import TinkLink
import TinkLinkUI

@objc(TinkLinkSDK)
class TinkLinkSDK: UIViewController {

  override func viewDidLoad() {
      super.viewDidLoad()
  }

  
  @objc
  private func startSDK(_ clientID: String, market: String, urlScheme: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
    DispatchQueue.main.async {

      let scopes: [Scope] = [
          // .statistics(.read),
          .transactions(.read),
          .categories(.read),
          .accounts(.read)
      ]
      
      let redirectURI = NSURL(string: "\(urlScheme)://tink-redirect")

      let configuration = try! Tink.Configuration(clientID: clientID, redirectURI: redirectURI! as URL)
      Tink.configure(with: configuration)

      let tinkLinkViewController = TinkLinkViewController(market: Market(rawValue: market)!, scopes: scopes, providerPredicate: .kinds(.all)) { (result) in
        // (Result<(code: AuthorizationCode, credentials: Credentials), TinkLinkError>)
        switch (result) {
        case .success(let data):
          return resolve(["code": data.code.rawValue])
        case .failure(let error):
          return reject("tink_failed", error.localizedDescription, nil)
        }

      }
      UIApplication.shared.windows.first?.rootViewController?.present(tinkLinkViewController, animated: true)
      }
    }
  }

then you can open it with NativeModules.TinkLinkSDK.startSDK

@maxencehenneron
Copy link

maxencehenneron commented Mar 2, 2021

@SuperDuperMartin Thank you for the sample code.

Did you get the following error while installing the tink link sdk on a react native project?

Undefined symbols for architecture x86_64:
  "protocol descriptor for Swift.Identifiable", referenced from:
      protocol conformance descriptor for TinkLink.AddCredentialsTask : Swift.Identifiable in TinkLink in libTinkLink.a(AddCredentialsTask.o)
      protocol conformance descriptor for TinkLink.ProviderTree.FinancialInstitutionGroupNode : Swift.Identifiable in TinkLink in libTinkLink.a(ProviderTree.o)
      protocol conformance descriptor for TinkLink.RefreshCredentialsTask : Swift.Identifiable in TinkLink in libTinkLink.a(RefreshCredentialsTask.o)
      protocol conformance descriptor for TinkLink.SupplementInformationTask : Swift.Identifiable in TinkLink in libTinkLink.a(SupplementInformationTask.o)
      protocol conformance descriptor for TinkLink.ThirdPartyAppAuthenticationTask : Swift.Identifiable in TinkLink in libTinkLink.a(ThirdPartyAppAuthenticationTask.o)
  "associated conformance descriptor for Swift.Identifiable.Swift.Identifiable.ID: Swift.Hashable", referenced from:
      protocol conformance descriptor for TinkLink.AddCredentialsTask : Swift.Identifiable in TinkLink in libTinkLink.a(AddCredentialsTask.o)

If so, were you able to resolve it?

EDIT: Found the issue: I fixed it by removing ""$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"", line from LIBRARY_SEARCH_PATHS in project.pbxproj file.

@ZiggerZZ
Copy link

@maxencehenneron @MartinInAction would you have a code snippet in Java/Kotlin for tink-link-android by any chance?

@MartinInAction
Copy link

MartinInAction commented Feb 2, 2022

Hi @ZiggerZZ, sorry for late replay, but yes i do!
something like this:

class TinkLinkManager(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), ActivityEventListener {
    override fun getName(): String {
        return "TinkLinkSDK"
    }
    init {
        reactApplicationContext.addActivityEventListener(this)
    }
    private var mPromise: Promise? = null

    @ReactMethod
    fun startSDK(clientId: String, authCode: String, market: String, urlScheme: String, redirectURI: String, promise: Promise) {
        this.mPromise = promise
        val linkUser = LinkUser.UnauthenticatedUser(authCode)
        val scopes = listOf(Scope.IdentityRead, Scope.UserRead, Scope.AccountsRead, Scope.TransactionsRead)
        val intent = TinkLinkUiActivity.createIntent(
                context = reactApplicationContext,
                linkUser = linkUser,
                scopes = scopes,
                credentialsOperation = CredentialsOperation.Create()
            )
        reactApplicationContext.startActivityForResult(intent, REQUEST_CODE, Bundle.EMPTY)        
    }

    override fun onActivityResult(activity: Activity?, requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == REQUEST_CODE) {
            when (resultCode) {
            TinkLinkUiActivity.RESULT_SUCCESS -> {
                when (
                    val result = data?.getParcelableExtra<TinkLinkResult>(TinkLinkUiActivity.RESULT_DATA)
                ) {
                    is TinkLinkResult.TemporaryUser -> {
                        mPromise?.reject("wrong type")
                    }

                    is TinkLinkResult.PermanentUser -> {
                        mPromise?.resolve("success")
                    }

                    else -> mPromise?.reject("error")
                }
            }

            TinkLinkUiActivity.RESULT_FAILURE -> {
                when (
                    val result = data?.getParcelableExtra<TinkLinkError>(TinkLinkUiActivity.ERROR_DATA)
                ) {
                    is TinkLinkError.FailedToAddCredentials -> {
                        for ((id, error) in result.errorsByCredentialsId) {
                            mPromise?.reject("error")
                        }
                    }
                }
            }

            TinkLinkUiActivity.RESULT_CANCELLED -> {
                // Toast.makeText(reactApplicationContext, "Cancelled", Toast.LENGTH_SHORT).show()
                mPromise?.resolve("cancelled")
            }
        }

        data?.getBundleExtra(TinkLinkUiActivity.FAILED_CREDENTIALS_DATA)
            ?.takeIf { !it.isEmpty }
            ?.let { bundle ->
                for (credentialsId in bundle.keySet()) {
                    val error = bundle.getParcelable<TinkLinkErrorInfo>(credentialsId)
                    mPromise?.reject("error")
                    // Handling logic such as deleting the credentials matching the credentialsId
                }
            }

        }
    }

    override fun onNewIntent(intent: Intent?) = Unit

    companion object {
        const val REQUEST_CODE = 100

        fun initializeTink(context: Context) {
            val linkConfig = TinkConfiguration(
                environment = Environment.Production,
                oAuthClientId = BuildConfig.TINK_CLIENT_ID,
                redirectUri = Uri.Builder()
                    .scheme(BuildConfig.URL_SCHEME)
                    .encodedAuthority(BuildConfig.TINK_URL_HOST)
                    .build()
            )
            Tink.init(linkConfig, context)
        }
    }
}

@ZiggerZZ
Copy link

ZiggerZZ commented Feb 2, 2022

@MartinInAction thanks! Does it work for you? I tried the official tutorial from Tink recently and the app kept loading infinitely.

@MartinInAction
Copy link

@ZiggerZZ its working yes! hmm, i think i had a similar issue, and i forgot to install AndroidThreeTen https://github.com/tink-ab/tink-link-android
See if that works! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants