From 5b36efacd6a3dae65a02af3cec220b467134663c Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 12 Dec 2023 16:57:38 -0800 Subject: [PATCH 01/10] Turbo module templating before codegen --- RTNWallet/android/build.gradle | 29 ++++++++ .../java/com/rtnwallet/WalletPackage.java | 24 +++++++ RTNWallet/js/NativeWallet.ts | 9 +++ RTNWallet/package.json | 71 +++++++++++++++++++ RTNWallet/rtn-wallet.podspec | 19 +++++ tsconfig.json | 2 +- 6 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 RTNWallet/android/build.gradle create mode 100644 RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java create mode 100644 RTNWallet/js/NativeWallet.ts create mode 100644 RTNWallet/package.json create mode 100644 RTNWallet/rtn-wallet.podspec diff --git a/RTNWallet/android/build.gradle b/RTNWallet/android/build.gradle new file mode 100644 index 000000000000..7f8a446a3df5 --- /dev/null +++ b/RTNWallet/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.safeExtGet = {prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + repositories { + google() + gradlePluginPortal() + } + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + } +} + +apply plugin: 'com.android.library' +apply plugin: 'com.facebook.react' + +android { + compileSdkVersion safeExtGet('compileSdkVersion', 33) + namespace "com.rtnwallet" +} + +repositories { + mavenCentral() + google() +} + +dependencies { + implementation 'com.facebook.react:react-native' +} \ No newline at end of file diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java new file mode 100644 index 000000000000..2b4fcd57c61c --- /dev/null +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java @@ -0,0 +1,24 @@ +package com.rtnwallet; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.Collections; +import java.util.List; + +public class WalletPackage extends TurboReactPackage { + + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + return null; + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return null; + } +} \ No newline at end of file diff --git a/RTNWallet/js/NativeWallet.ts b/RTNWallet/js/NativeWallet.ts new file mode 100644 index 000000000000..f5dd52cf097a --- /dev/null +++ b/RTNWallet/js/NativeWallet.ts @@ -0,0 +1,9 @@ +import {TurboModule, TurboModuleRegistry} from 'react-native'; + +export interface Spec extends TurboModule { + add(a: number, b: number): Promise; +} + +export default TurboModuleRegistry.get( + 'RTNWallet', +) as Spec | null; diff --git a/RTNWallet/package.json b/RTNWallet/package.json new file mode 100644 index 000000000000..88280e436720 --- /dev/null +++ b/RTNWallet/package.json @@ -0,0 +1,71 @@ +{ + "name": "react-native-wallet", + "version": "0.0.1", + "description": "A cross platform native module for React-Native to add payment cards to Apple Pay and Google Pay", + "main": "index.js", + "scripts": { + "build": "echo \"Warning: no build process has been specified yet\"", + "lint": "eslint index.js", + "prettier": "prettier --write .", + "prettier-watch": "onchange \"**/*.js\" -- prettier --write --ignore-unknown {{changed}}", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Expensify/react-native-wallet.git" + }, + "files": [ + "js", + "android", + "ios", + "rtn-wallet.podspec", + "!android/build", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__" + ], + "keywords": [ + "React", + "React-Native", + "Passkit", + "Wallet" + ], + "author": "Expensify, Inc.", + "license": "MIT", + "bugs": { + "url": "https://github.com/Expensify/react-native-wallet/issues" + }, + "homepage": "https://github.com/Expensify/react-native-wallet#readme", + "devDependencies": { + "@babel/core": "7.20.12", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.2.5", + "eslint": "^7.6.0", + "eslint-config-expensify": "^2.0.24", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-react": "^7.31.10", + "metro-react-native-babel-preset": "^0.72.3", + "prettier": "^2.8.8" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "engines": { + "node": "16.15.1", + "npm": "8.11.0" + }, + "codegenConfig": { + "name": "RTNWalletSpec", + "type": "modules", + "jsSrcsDir": "js", + "android": { + "javaPackageName": "com.rtnwallet" + } + } + } + \ No newline at end of file diff --git a/RTNWallet/rtn-wallet.podspec b/RTNWallet/rtn-wallet.podspec new file mode 100644 index 000000000000..6c1ffdd1b4cf --- /dev/null +++ b/RTNWallet/rtn-wallet.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "rtn-wallet" + s.version = package["version"] + s.summary = package["description"] + s.description = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.platforms = { :ios => "11.0" } + s.author = package["author"] + s.source = { :git => package["repository"], :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + install_modules_dependencies(s) +end \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 08447f306dd5..dcd93bbd5bd1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -47,5 +47,5 @@ } }, "exclude": ["**/node_modules/*", "**/dist/*", ".github/actions/**/index.js", "**/docs/*"], - "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*"] + "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*", "**/RTNWallet/*"] } From e49e6836085ccbb7573be72c06632e0474782bc5 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 12 Dec 2023 17:22:09 -0800 Subject: [PATCH 02/10] Post codegen --- RTNWallet/package.json | 4 +- package-lock.json | 523 +++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 526 insertions(+), 2 deletions(-) diff --git a/RTNWallet/package.json b/RTNWallet/package.json index 88280e436720..bae47cc19453 100644 --- a/RTNWallet/package.json +++ b/RTNWallet/package.json @@ -56,8 +56,8 @@ "react-native": "*" }, "engines": { - "node": "16.15.1", - "npm": "8.11.0" + "node": "20.9.0", + "npm": "10.1.0" }, "codegenConfig": { "name": "RTNWalletSpec", diff --git a/package-lock.json b/package-lock.json index 63179219c300..3dd1dd80fae9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,6 +109,7 @@ "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "^3.6.0", "react-native-vision-camera": "^2.16.2", + "react-native-wallet": "file:RTNWallet", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-webview": "^11.17.2", @@ -44725,6 +44726,10 @@ "react-native": "*" } }, + "node_modules/react-native-wallet": { + "resolved": "RTNWallet", + "link": true + }, "node_modules/react-native-web": { "version": "0.19.9", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.9.tgz", @@ -52968,6 +52973,303 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } + }, + "RTNWallet": { + "version": "0.0.1", + "license": "MIT", + "devDependencies": { + "@babel/core": "7.20.12", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.2.5", + "eslint": "^7.6.0", + "eslint-config-expensify": "^2.0.24", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-react": "^7.31.10", + "metro-react-native-babel-preset": "^0.72.3", + "prettier": "^2.8.8" + }, + "engines": { + "node": "20.9.0", + "npm": "10.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "RTNWallet/node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "RTNWallet/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "RTNWallet/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "RTNWallet/node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "RTNWallet/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "RTNWallet/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "RTNWallet/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "RTNWallet/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "RTNWallet/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "RTNWallet/node_modules/metro-react-native-babel-preset": { + "version": "0.72.4", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.4.tgz", + "integrity": "sha512-YGCVaYe1H5fOFktdDdL9IwAyiXjPh1t2eZZFp3KFJak6fxKpN+q5PPhe1kzMa77dbCAqgImv43zkfGa6i27eyA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.14.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "react-refresh": "^0.4.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "RTNWallet/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "RTNWallet/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "RTNWallet/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "RTNWallet/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "RTNWallet/node_modules/react-refresh": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", + "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "RTNWallet/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "RTNWallet/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } } }, "dependencies": { @@ -84997,6 +85299,227 @@ "integrity": "sha512-QIpG33l3QB0AkTfX/ccRknwNRu1APNUkokVKF1lpRO2+tBnkXnGL0UapgXg5u9KIONZtrpupeDeO+J5B2TeQVw==", "requires": {} }, + "react-native-wallet": { + "version": "file:RTNWallet", + "requires": { + "@babel/core": "7.20.12", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.2.5", + "eslint": "^7.6.0", + "eslint-config-expensify": "^2.0.24", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-react": "^7.31.10", + "metro-react-native-babel-preset": "^0.72.3", + "prettier": "^2.8.8" + }, + "dependencies": { + "@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "metro-react-native-babel-preset": { + "version": "0.72.4", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.4.tgz", + "integrity": "sha512-YGCVaYe1H5fOFktdDdL9IwAyiXjPh1t2eZZFp3KFJak6fxKpN+q5PPhe1kzMa77dbCAqgImv43zkfGa6i27eyA==", + "dev": true, + "requires": { + "@babel/core": "^7.14.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "react-refresh": "^0.4.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "react-refresh": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", + "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, "react-native-web": { "version": "0.19.9", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.9.tgz", diff --git a/package.json b/package.json index e03beed0bd8e..9fb40adf96c7 100644 --- a/package.json +++ b/package.json @@ -157,6 +157,7 @@ "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "^3.6.0", "react-native-vision-camera": "^2.16.2", + "react-native-wallet": "file:RTNWallet", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-webview": "^11.17.2", From 1a9e5d5d12c3ffc621b022ba49c46f15176eb336 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 12 Dec 2023 17:50:01 -0800 Subject: [PATCH 03/10] Update the function declaration to handle an object for each platform specific implementation --- .../main/java/com/rtnwallet/WalletModule.kt | 17 +++++++++ .../java/com/rtnwallet/WalletPackage.java | 24 ------------- .../main/java/com/rtnwallet/WalletPackage.kt | 12 +++++++ RTNWallet/js/NativeWallet.ts | 36 ++++++++++++++++--- 4 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt delete mode 100644 RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java create mode 100644 RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt new file mode 100644 index 000000000000..acc253726209 --- /dev/null +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt @@ -0,0 +1,17 @@ +package com.rtnwallet + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.rtnwallet.NativeWalletSpec + +class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext) { + override fun getName() = NAME + + override fun add(a: Double, b: Double, promise: Promise) { + promise.resolve(a + b) + } + + companion object { + const val NAME = "RTNWallet" + } +} diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java deleted file mode 100644 index 2b4fcd57c61c..000000000000 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.rtnwallet; - -import androidx.annotation.Nullable; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.module.model.ReactModuleInfoProvider; -import com.facebook.react.TurboReactPackage; - -import java.util.Collections; -import java.util.List; - -public class WalletPackage extends TurboReactPackage { - - @Nullable - @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { - return null; - } - - @Override - public ReactModuleInfoProvider getReactModuleInfoProvider() { - return null; - } -} \ No newline at end of file diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt new file mode 100644 index 000000000000..210d620ee89a --- /dev/null +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt @@ -0,0 +1,12 @@ +package com.rtnwallet; + +import com.facebook.react.TurboReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfoProvider + +class CalculatorPackage : TurboReactPackage() { + override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? = null + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider? = null +} diff --git a/RTNWallet/js/NativeWallet.ts b/RTNWallet/js/NativeWallet.ts index f5dd52cf097a..fbc558dae6ac 100644 --- a/RTNWallet/js/NativeWallet.ts +++ b/RTNWallet/js/NativeWallet.ts @@ -1,9 +1,37 @@ import {TurboModule, TurboModuleRegistry} from 'react-native'; export interface Spec extends TurboModule { - add(a: number, b: number): Promise; + + // Method to create a digital wallet with platform-specific parameters + createDigitalWallet(params: { + // General parameter for both platforms + appVersion: string, + + // Android-specific parameters + walletAccountID?: string, + deviceID?: string, + + // iOS-specific parameters + certificates?: string, + nonce?: string, + nonceSignature?: string + }): Promise<{ + // General return value for both platforms + cardToken: string, + + // Android-specific return values + opaquePaymentCard?: string, + userAddress?: string, + network?: string, + tokenServiceProvider?: string, + displayName?: string, + lastDigits?: string, + + // iOS-specific return values + encryptedPassData?: string, + activationData?: string, + ephemeralPublicKey?: string + }>; } -export default TurboModuleRegistry.get( - 'RTNWallet', -) as Spec | null; +export default TurboModuleRegistry.get('RTNWallet'); From 0ad718cf9b3227e3ac02c0a15a5cdbfeffbacdc0 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 11:00:45 -0800 Subject: [PATCH 04/10] Add implementation for Android createDigitalWallet --- .../main/java/com/rtnwallet/WalletModule.kt | 41 +++++++++++++++---- .../main/java/com/rtnwallet/WalletPackage.kt | 16 +++++--- RTNWallet/js/NativeWallet.ts | 24 ++++++++--- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt index acc253726209..5a7264104ad3 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt @@ -2,16 +2,39 @@ package com.rtnwallet import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext -import com.rtnwallet.NativeWalletSpec +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.turbomodule.core.interfaces.TurboModule -class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext) { - override fun getName() = NAME +@ReactModule(name = WalletModule.NAME) +class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext), TurboModule { - override fun add(a: Double, b: Double, promise: Promise) { - promise.resolve(a + b) - } + override fun createDigitalWallet(params: ReadableMap, promise: Promise) { + try { + val paramMap = params.toHashMap() as Map - companion object { - const val NAME = "RTNWallet" - } + // Extract common parameters + val appVersion = paramMap["appVersion"] as? String ?: throw Exception("appVersion is required") + + // Extract Android specific parameters + val walletAccountID = paramMap["walletAccountID"] as? String + val deviceID = paramMap["deviceID"] as? String + + // Call Android specific method in WalletManager with these parameters + val result = WalletManager.createDigitalWalletForAndroid(appVersion, walletAccountID, deviceID) + // Convert the result to a WritableMap and resolve the promise + promise.resolve(convertMapToWritableMap(result)) + } catch (e: Exception) { + promise.reject("CREATE_WALLET_ERROR", e.message) + } + } + + companion object { + const val NAME = "RTNWallet" + } + + // Helper function to convert Map to WritableMap + private fun convertMapToWritableMap(map: Map): WritableMap { + // Implementation... + } } diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt index 210d620ee89a..d693032b7fd8 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt @@ -1,12 +1,16 @@ -package com.rtnwallet; +package com.rtnwallet -import com.facebook.react.TurboReactPackage +import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.uimanager.ViewManager -class CalculatorPackage : TurboReactPackage() { - override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? = null +class WalletPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf(WalletModule(reactContext)) + } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider? = null + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return emptyList() + } } diff --git a/RTNWallet/js/NativeWallet.ts b/RTNWallet/js/NativeWallet.ts index fbc558dae6ac..b0bc0fade1a5 100644 --- a/RTNWallet/js/NativeWallet.ts +++ b/RTNWallet/js/NativeWallet.ts @@ -1,16 +1,13 @@ -import {TurboModule, TurboModuleRegistry} from 'react-native'; +import { TurboModule, TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { - // Method to create a digital wallet with platform-specific parameters createDigitalWallet(params: { // General parameter for both platforms appVersion: string, - // Android-specific parameters walletAccountID?: string, deviceID?: string, - // iOS-specific parameters certificates?: string, nonce?: string, @@ -18,7 +15,6 @@ export interface Spec extends TurboModule { }): Promise<{ // General return value for both platforms cardToken: string, - // Android-specific return values opaquePaymentCard?: string, userAddress?: string, @@ -26,12 +22,28 @@ export interface Spec extends TurboModule { tokenServiceProvider?: string, displayName?: string, lastDigits?: string, - // iOS-specific return values encryptedPassData?: string, activationData?: string, ephemeralPublicKey?: string }>; + + // Sets the callback for wallet creation + setCreateWalletCallback(callback: Function): Promise; + + // Sets the callback for refreshing card list + setRefreshCardListCallback(callback: Function): Promise; + + // Sets the callback for handling errors + setHadErrorCallback(callback: Function): Promise; + + // Gets device and wallet information + getDeviceInfo(): Promise<{ walletId: string, hardwareId: string }>; + + handleWalletCreationResponse(data: object): Promise; + + // Registers for data changes in the wallet + registerDataChanged(): Promise; } export default TurboModuleRegistry.get('RTNWallet'); From 1ace7cc3131dee66a73e16f0ce04fd88ed63eba0 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 11:07:11 -0800 Subject: [PATCH 05/10] Update WalletPackage.kt --- .../main/java/com/rtnwallet/WalletPackage.kt | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt index d693032b7fd8..e873fbe95cd9 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt @@ -1,16 +1,32 @@ package com.rtnwallet -import com.facebook.react.ReactPackage +import com.facebook.react.TurboReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.ViewManager +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider -class WalletPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf(WalletModule(reactContext)) - } +class WalletPackage : TurboReactPackage() { + override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? = + if (name == WalletModule.NAME) { + WalletModule(reactContext) + } else { + null + } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return emptyList() + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + mapOf( + WalletModule.NAME to ReactModuleInfo( + WalletModule.NAME, + WalletModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + true // isTurboModule + ) + ) + } } } From 5b91cc769238e33c8001315f9f8d53f26e7b244d Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 11:46:26 -0800 Subject: [PATCH 06/10] Update the signatures, I messed up the neccesary methods --- .../main/java/com/rtnwallet/WalletModule.kt | 30 +++------ .../main/java/com/rtnwallet/WalletPackage.kt | 24 ++++--- RTNWallet/js/NativeWallet.ts | 64 +++++++------------ 3 files changed, 43 insertions(+), 75 deletions(-) diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt index 5a7264104ad3..f86993af62c2 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt @@ -5,36 +5,26 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableMap import com.facebook.react.module.annotations.ReactModule import com.facebook.react.turbomodule.core.interfaces.TurboModule +import com.rtnwallet.managers.WalletManager // Adjust with your actual manager @ReactModule(name = WalletModule.NAME) class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext), TurboModule { - override fun createDigitalWallet(params: ReadableMap, promise: Promise) { - try { - val paramMap = params.toHashMap() as Map + override fun getDeviceDetails(promise: Promise) { + // Implementation to retrieve device-specific details + // ... - // Extract common parameters - val appVersion = paramMap["appVersion"] as? String ?: throw Exception("appVersion is required") + promise.resolve(/* Your result here */) + } - // Extract Android specific parameters - val walletAccountID = paramMap["walletAccountID"] as? String - val deviceID = paramMap["deviceID"] as? String + override fun handleWalletCreationResponse(data: ReadableMap, promise: Promise) { + // Convert ReadableMap to Kotlin Map and handle the wallet creation response + // ... - // Call Android specific method in WalletManager with these parameters - val result = WalletManager.createDigitalWalletForAndroid(appVersion, walletAccountID, deviceID) - // Convert the result to a WritableMap and resolve the promise - promise.resolve(convertMapToWritableMap(result)) - } catch (e: Exception) { - promise.reject("CREATE_WALLET_ERROR", e.message) - } + promise.resolve(true) // Or handle with appropriate success/error response } companion object { const val NAME = "RTNWallet" } - - // Helper function to convert Map to WritableMap - private fun convertMapToWritableMap(map: Map): WritableMap { - // Implementation... - } } diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt index e873fbe95cd9..235c41793950 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletPackage.kt @@ -14,19 +14,17 @@ class WalletPackage : TurboReactPackage() { null } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { - return ReactModuleInfoProvider { - mapOf( - WalletModule.NAME to ReactModuleInfo( - WalletModule.NAME, - WalletModule.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true // isTurboModule - ) + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { + mapOf( + WalletModule.NAME to ReactModuleInfo( + WalletModule.NAME, + WalletModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + true // isTurboModule ) - } + ) } } diff --git a/RTNWallet/js/NativeWallet.ts b/RTNWallet/js/NativeWallet.ts index b0bc0fade1a5..f6075cc8abb5 100644 --- a/RTNWallet/js/NativeWallet.ts +++ b/RTNWallet/js/NativeWallet.ts @@ -1,49 +1,29 @@ -import { TurboModule, TurboModuleRegistry } from 'react-native'; +import {TurboModule, TurboModuleRegistry} from 'react-native'; export interface Spec extends TurboModule { - // Method to create a digital wallet with platform-specific parameters - createDigitalWallet(params: { - // General parameter for both platforms - appVersion: string, - // Android-specific parameters - walletAccountID?: string, - deviceID?: string, - // iOS-specific parameters - certificates?: string, - nonce?: string, - nonceSignature?: string - }): Promise<{ - // General return value for both platforms - cardToken: string, - // Android-specific return values - opaquePaymentCard?: string, - userAddress?: string, - network?: string, - tokenServiceProvider?: string, - displayName?: string, - lastDigits?: string, - // iOS-specific return values - encryptedPassData?: string, - activationData?: string, - ephemeralPublicKey?: string + // Method to get device details for wallet creation + getDeviceDetails(): Promise<{ + walletAccountID?: string; // Android + deviceID?: string; // Android + // Add any iOS-specific details if needed }>; - // Sets the callback for wallet creation - setCreateWalletCallback(callback: Function): Promise; - - // Sets the callback for refreshing card list - setRefreshCardListCallback(callback: Function): Promise; - - // Sets the callback for handling errors - setHadErrorCallback(callback: Function): Promise; - - // Gets device and wallet information - getDeviceInfo(): Promise<{ walletId: string, hardwareId: string }>; - - handleWalletCreationResponse(data: object): Promise; - - // Registers for data changes in the wallet - registerDataChanged(): Promise; + // Method to handle wallet creation response + handleWalletCreationResponse(data: { + // Common return values + cardToken: string; + // Android-specific return values + opaquePaymentCard?: string; + userAddress?: string; + network?: string; + tokenServiceProvider?: string; + displayName?: string; + lastDigits?: string; + // iOS-specific return values + encryptedPassData?: string; + activationData?: string; + ephemeralPublicKey?: string; + }): Promise; } export default TurboModuleRegistry.get('RTNWallet'); From 58d7c66300a3b06dfda5c8d16b80a741bcb937d4 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 12:03:00 -0800 Subject: [PATCH 07/10] Finish implementing getDeviceDetails for android --- .../main/java/com/rtnwallet/WalletModule.kt | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt index f86993af62c2..8576d54addbe 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt @@ -11,12 +11,38 @@ import com.rtnwallet.managers.WalletManager // Adjust with your actual manager class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext), TurboModule { override fun getDeviceDetails(promise: Promise) { - // Implementation to retrieve device-specific details - // ... + var walletIDError: Exception? = null + var hardwareIDError: Exception? = null + lateinit var walletID: String + lateinit var hardwareID: String + + // Get Wallet ID + getWalletID { id, error -> + if (error != null) walletIDError = error + else walletID = id ?: "" + } + + // Get Hardware ID + getHardwareID { id, error -> + if (error != null) hardwareIDError = error + else hardwareID = id ?: "" + } - promise.resolve(/* Your result here */) + // Check results and resolve/reject promise + when { + walletIDError != null -> promise.reject("WALLET_ID_ERROR", "Failed to retrieve Wallet ID", walletIDError) + hardwareIDError != null -> promise.reject("HARDWARE_ID_ERROR", "Failed to retrieve Hardware ID", hardwareIDError) + else -> { + val result = WritableNativeMap().apply { + putString("walletID", walletID) + putString("hardwareID", hardwareID) + } + promise.resolve(result) + } + } } + override fun handleWalletCreationResponse(data: ReadableMap, promise: Promise) { // Convert ReadableMap to Kotlin Map and handle the wallet creation response // ... @@ -24,6 +50,27 @@ class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(rea promise.resolve(true) // Or handle with appropriate success/error response } + private fun getWalletID(completion: (String?, Exception?) -> Unit) { + tapAndPayClient.activewalletID.addOnCompleteListener { task -> + if (task.isSuccessful && task.result != null) { + completion(task.result, null) + } else { + completion(null, task.exception) + } + } + } + + private fun getHardwareID(completion: (String?, Exception?) -> Unit) { + tapAndPayClient.stablehardwareID.addOnCompleteListener { task -> + if (task.isSuccessful && task.result != null) { + completion(task.result, null) + } else { + completion(null, task.exception) + } + } + } + + companion object { const val NAME = "RTNWallet" } From dd5b4fe9fae119f7d5e5ee2ff97dab9e4a94b72a Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 12:30:24 -0800 Subject: [PATCH 08/10] Finish native android implementation --- .../main/java/com/rtnwallet/WalletModule.kt | 127 ++++++++++++++---- 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt index 8576d54addbe..13dbf5a2c8b9 100644 --- a/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt +++ b/RTNWallet/android/src/main/java/com/rtnwallet/WalletModule.kt @@ -5,49 +5,120 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableMap import com.facebook.react.module.annotations.ReactModule import com.facebook.react.turbomodule.core.interfaces.TurboModule -import com.rtnwallet.managers.WalletManager // Adjust with your actual manager +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.tapandpay.TapAndPay +import com.google.android.gms.tapandpay.TapAndPayClient +import com.google.android.gms.tapandpay.TapAndPayStatusCodes +import com.google.android.gms.tapandpay.issuer.PushTokenizeRequest +import com.google.android.gms.tapandpay.issuer.UserAddress +import kotlinx.coroutines.* + @ReactModule(name = WalletModule.NAME) class WalletModule(reactContext: ReactApplicationContext) : NativeWalletSpec(reactContext), TurboModule { - - override fun getDeviceDetails(promise: Promise) { - var walletIDError: Exception? = null - var hardwareIDError: Exception? = null - lateinit var walletID: String - lateinit var hardwareID: String - - // Get Wallet ID - getWalletID { id, error -> - if (error != null) walletIDError = error - else walletID = id ?: "" + private class WalletCreationItem(val model: Map) { + object Keys { + const val tokenServiceProvider = "tokenServiceProvider" + const val network = "network" + const val opaquePaymentCard = "opaquePaymentCard" + const val displayName = "displayName" + const val lastDigits = "lastDigits" + const val name = "name" + const val phone = "phone" + const val userAddress = "userAddress" + const val address1 = "address1" + const val address2 = "address2" + const val city = "city" + const val state = "state" + const val country = "country" + const val postal_code = "postal_code" } - // Get Hardware ID - getHardwareID { id, error -> - if (error != null) hardwareIDError = error - else hardwareID = id ?: "" - } + private val addressData: Map + get() = model[Keys.userAddress] as? Map ?: HashMap() + + val tokenServiceProvider: Int + get() = when ((model[Keys.tokenServiceProvider] as? String ?: "").toUpperCase()) { + "TOKEN_PROVIDER_AMEX" -> TapAndPay.TOKEN_PROVIDER_AMEX + "TOKEN_PROVIDER_MASTERCARD" -> TapAndPay.TOKEN_PROVIDER_MASTERCARD + "TOKEN_PROVIDER_VISA" -> TapAndPay.TOKEN_PROVIDER_VISA + "TOKEN_PROVIDER_DISCOVER" -> TapAndPay.TOKEN_PROVIDER_DISCOVER + else -> 1000 + } + + val network: Int + get() = when ((model[Keys.network] as? String ?: "").toUpperCase()) { + "AMEX" -> TapAndPay.CARD_NETWORK_AMEX + "DISCOVER" -> TapAndPay.CARD_NETWORK_DISCOVER + "MASTERCARD" -> TapAndPay.CARD_NETWORK_MASTERCARD + "VISA" -> TapAndPay.CARD_NETWORK_VISA + else -> 1000 + } + + val opcBytes: ByteArray + get() = (model[Keys.opaquePaymentCard] as? String ?: "").toByteArray() + + val displayName: String + get() = model[Keys.displayName] as? String ?: "" - // Check results and resolve/reject promise - when { - walletIDError != null -> promise.reject("WALLET_ID_ERROR", "Failed to retrieve Wallet ID", walletIDError) - hardwareIDError != null -> promise.reject("HARDWARE_ID_ERROR", "Failed to retrieve Hardware ID", hardwareIDError) - else -> { + val lastDigits: String + get() = model[Keys.lastDigits] as? String ?: "" + + val userAddress: UserAddress + get() = UserAddress.newBuilder() + .setName(addressData[Keys.name] as? String ?: "") + .setAddress1(addressData[Keys.address1] as? String ?: "") + .setAddress2(addressData[Keys.address2] as? String ?: "") + .setLocality(addressData[Keys.city] as? String ?: "") + .setAdministrativeArea(addressData[Keys.state] as? String ?: "") + .setCountryCode(addressData[Keys.country] as? String ?: "") + .setPostalCode(addressData[Keys.postal_code] as? String ?: "") + .setPhoneNumber(addressData[Keys.phone] as? String ?: "") + .build() + } + + private val tapAndPayClient: TapAndPayClient by lazy { + TapAndPay.getClient(reactContext.currentActivity ?: throw Exception("Current Activity not found")) + } + + private val coroutineScope = CoroutineScope(Dispatchers.Main + Job()) + + override fun getDeviceDetails(promise: Promise) { + coroutineScope.launch { + try { + val walletID = async(Dispatchers.IO) { getWalletID() } + val hardwareID = async(Dispatchers.IO) { getHardwareID() } val result = WritableNativeMap().apply { - putString("walletID", walletID) - putString("hardwareID", hardwareID) + putString("walletID", walletID.await()) + putString("hardwareID", hardwareID.await()) } promise.resolve(result) + } catch (e: Exception) { + promise.reject("DEVICE_DETAILS_ERROR", "Failed to retrieve device details", e) } } } override fun handleWalletCreationResponse(data: ReadableMap, promise: Promise) { - // Convert ReadableMap to Kotlin Map and handle the wallet creation response - // ... - - promise.resolve(true) // Or handle with appropriate success/error response + try { + val context = reactContext.currentActivity ?: throw Exception("Current Activity not found") + val walletCreationItem = WalletCreationItem(data) + val pushTokenizeRequest = PushTokenizeRequest.Builder() + .setOpaquePaymentCard(walletCreationItem.opcBytes) + .setNetwork(walletCreationItem.network) + .setTokenServiceProvider(walletCreationItem.tokenServiceProvider) + .setDisplayName(walletCreationItem.displayName) + .setLastDigits(walletCreationItem.lastDigits) + .setUserAddress(walletCreationItem.userAddress) + .build() + tapAndPayClient.pushTokenize(context, pushTokenizeRequest, requestPushTokenize) + + // Assuming success handling here. Adjust according to actual process + promise.resolve(null) + } catch (e: Exception) { + promise.reject("WALLET_CREATION_ERROR", "Failed to add card to Google Pay", e) + } } private fun getWalletID(completion: (String?, Exception?) -> Unit) { From e83066d6c9cd61b4b608a00b2309c7e8d1086094 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 12:53:50 -0800 Subject: [PATCH 09/10] Enable new architecture Android --- android/gradle.properties | 2 +- package-lock.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/android/gradle.properties b/android/gradle.properties index 0de47ef7d184..7209f9573a0a 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -40,7 +40,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/package-lock.json b/package-lock.json index 3dd1dd80fae9..88f72f88959d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52975,6 +52975,7 @@ } }, "RTNWallet": { + "name": "react-native-wallet", "version": "0.0.1", "license": "MIT", "devDependencies": { From bacfafb50f0ccd19a261224da4e371a55f9e08e8 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 13 Dec 2023 14:39:31 -0800 Subject: [PATCH 10/10] Add template for iOS data --- RTNWallet/ios/RTNWallet.h | 9 +++++++++ RTNWallet/ios/RTNWallet.mm | 34 ++++++++++++++++++++++++++++++++ RTNWallet/ios/rtn-wallet.podspec | 19 ++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 RTNWallet/ios/RTNWallet.h create mode 100644 RTNWallet/ios/RTNWallet.mm create mode 100644 RTNWallet/ios/rtn-wallet.podspec diff --git a/RTNWallet/ios/RTNWallet.h b/RTNWallet/ios/RTNWallet.h new file mode 100644 index 000000000000..9a70bb74651e --- /dev/null +++ b/RTNWallet/ios/RTNWallet.h @@ -0,0 +1,9 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RTNWallet : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/RTNWallet/ios/RTNWallet.mm b/RTNWallet/ios/RTNWallet.mm new file mode 100644 index 000000000000..c8b2ec1c07cb --- /dev/null +++ b/RTNWallet/ios/RTNWallet.mm @@ -0,0 +1,34 @@ +#import "RTNWalletSpec.h" +#import "RTNWallet.h" + +@implementation RTNWallet + +RCT_EXPORT_MODULE(); + +RCT_EXPORT_METHOD(handleWalletCreationResponse:(NSDictionary *)data + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + + NSString *encryptedPassData = data[@"encryptedPassData"]; + NSString *activationData = data[@"activationData"]; + NSString *ephemeralPublicKey = data[@"ephemeralPublicKey"]; + + // Convert strings to NSData + NSData *encryptedPassDataBytes = [[NSData alloc] initWithBase64EncodedString:encryptedPassData options:0]; + NSData *activationDataBytes = [[NSData alloc] initWithBase64EncodedString:activationData options:0]; + NSData *ephemeralPublicKeyBytes = [[NSData alloc] initWithBase64EncodedString:ephemeralPublicKey options:0]; + + if (!encryptedPassDataBytes || !activationDataBytes || !ephemeralPublicKeyBytes) { + reject(@"ERROR", @"Invalid data provided", nil); + return; + } + + +} + +RCT_EXPORT_METHOD(getDeviceDetails:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + +} + +@end diff --git a/RTNWallet/ios/rtn-wallet.podspec b/RTNWallet/ios/rtn-wallet.podspec new file mode 100644 index 000000000000..283441984665 --- /dev/null +++ b/RTNWallet/ios/rtn-wallet.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "rtn-wallet" + s.version = package["version"] + s.summary = package["description"] + s.description = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.platforms = { :ios => "11.0" } + s.author = package["author"] + s.source = { :git => package["repository"], :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + install_modules_dependencies(s) +end