commit dd42dc04ce66426e1be967064c8957403104a460 Author: condiqiu Date: Fri Feb 13 07:17:40 2026 +0000 上传文件至 / diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..53d4b9f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [1.0.0] - 2024-01-XX + +### Added +- Initial release with Turbo Modules support +- Swift implementation for iOS +- Kotlin implementation for Android +- Support for latest Braintree SDK versions: + - iOS: Braintree 6.0, BraintreeDropIn 9.0 + - Android: Drop-In 6.16.0, Card 4.45.0 +- Apple Pay support (iOS) +- Google Pay support (Android) +- Venmo payment support +- PayPal payment support +- 3D Secure authentication +- Direct card tokenization +- Device data collection for fraud detection +- Vault manager support +- Dark theme support (iOS) +- Custom font support (iOS) +- TypeScript definitions +- Comprehensive documentation and examples + +### Features +- Full React Native New Architecture compatibility +- Backward compatible with old architecture +- Promise-based API +- Detailed error handling +- Latest payment methods support + +### Technical +- Built with React Native 0.73 compatibility +- Minimum iOS version: 13.0 +- Minimum Android SDK: 21 +- Swift 5.0 +- Kotlin 1.8.21 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..85f53f0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 [Your Name] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..ffec253 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,402 @@ +# Migration Guide + +## Migrating from Old Braintree Drop-In Implementation + +This guide helps you migrate from the legacy Braintree implementation to the new Turbo Module version. + +## Key Differences + +### Architecture +- **Old**: Bridge-based module +- **New**: Turbo Module with full New Architecture support + +### SDK Versions +- **iOS**: Upgraded to Braintree 6.0, BraintreeDropIn 9.0 +- **Android**: Upgraded to Drop-In 6.16.0, Card 4.45.0 + +### Language +- **iOS**: Migrated from Objective-C to Swift +- **Android**: Migrated from Java to Kotlin + +## Breaking Changes + +### 1. Import Statement + +**Old:** +```javascript +import RNBraintreeDropIn from 'react-native-braintree-dropin'; +``` + +**New:** +```typescript +import BraintreeDropIn from 'react-native-braintree-dropin-turbo'; +``` + +### 2. Method Calls + +**Old:** +```javascript +RNBraintreeDropIn.show(options) + .then(result => { + console.log(result.nonce); + }) + .catch(error => { + console.error(error); + }); +``` + +**New:** +```typescript +try { + const result = await BraintreeDropIn.show(options); + console.log(result.nonce); +} catch (error) { + console.error(error); +} +``` + +### 3. Options Structure + +Most options remain the same, but there are some changes: + +**Old:** +```javascript +{ + clientToken: 'token', + darkTheme: true, + merchantIdentifier: 'merchant.id', // iOS + // ... +} +``` + +**New (unchanged, but TypeScript-typed):** +```typescript +{ + clientToken: 'token', + darkTheme: true, + merchantIdentifier: 'merchant.id', + // ... +}: DropInOptions +``` + +### 4. Android Setup Changes + +**Old:** +```java +// No special initialization needed +``` + +**New:** +```kotlin +import com.braintreedroptinturbo.RNBraintreeDropInModule + +class MainActivity : FragmentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + RNBraintreeDropInModule.initDropInClient(this) + } +} +``` + +**Important:** MainActivity must now extend `FragmentActivity` instead of `ReactActivity`. + +### 5. Package Name Changes + +**Old (AndroidManifest.xml):** +```xml + +``` + +**New:** +```kotlin +package com.braintreedroptinturbo +``` + +### 6. iOS Podspec + +**Old:** +```ruby +pod 'RNBraintreeDropIn', :path => '../node_modules/react-native-braintree-dropin' +``` + +**New (auto-linked):** +```ruby +# No manual podspec needed - auto-linked +# Or if manual: +pod 'react-native-braintree-dropin-turbo', :path => '../node_modules/react-native-braintree-dropin-turbo' +``` + +## Step-by-Step Migration + +### Step 1: Uninstall Old Package + +```bash +npm uninstall react-native-braintree-dropin +# or +yarn remove react-native-braintree-dropin +``` + +### Step 2: Clean iOS Pods + +```bash +cd ios +rm -rf Pods Podfile.lock +cd .. +``` + +### Step 3: Install New Package + +```bash +npm install react-native-braintree-dropin-turbo +# or +yarn add react-native-braintree-dropin-turbo +``` + +### Step 4: Update iOS + +```bash +cd ios +pod install +cd .. +``` + +### Step 5: Update Android MainActivity + +Update your `MainActivity.kt` (or convert from .java to .kt): + +```kotlin +import android.os.Bundle +import androidx.fragment.app.FragmentActivity +import com.braintreedroptinturbo.RNBraintreeDropInModule + +class MainActivity : FragmentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + RNBraintreeDropInModule.initDropInClient(this) + } + + // If you have other ReactActivity methods, you may need to adjust them +} +``` + +### Step 6: Update Import Statements + +Find and replace in your codebase: + +```bash +# Find +import RNBraintreeDropIn from 'react-native-braintree-dropin'; + +# Replace with +import BraintreeDropIn from 'react-native-braintree-dropin-turbo'; +``` + +### Step 7: Update Method Calls + +Convert from promise chains to async/await (recommended): + +**Before:** +```javascript +RNBraintreeDropIn.show(options) + .then(result => { + // handle result + }) + .catch(error => { + // handle error + }); +``` + +**After:** +```typescript +try { + const result = await BraintreeDropIn.show(options); + // handle result +} catch (error) { + // handle error +} +``` + +### Step 8: Add TypeScript Types (Optional but Recommended) + +If using TypeScript, add proper typing: + +```typescript +import BraintreeDropIn, { + type DropInOptions, + type PaymentResult +} from 'react-native-braintree-dropin-turbo'; + +const options: DropInOptions = { + clientToken: 'your-token', + orderTotal: 10.00, + // ... +}; + +const result: PaymentResult = await BraintreeDropIn.show(options); +``` + +### Step 9: Test Thoroughly + +Test all payment flows: +- Credit/Debit cards +- Apple Pay (iOS) +- Google Pay (Android) +- Venmo +- PayPal +- 3D Secure + +## API Changes + +### Unchanged Methods + +These methods work the same way: +- `show(options)` - Display Drop-In UI +- `fetchMostRecentPaymentMethod(clientToken)` - Get last payment method +- `tokenizeCard(clientToken, cardInfo)` - Tokenize a card + +### New Methods + +- `collectDeviceData(clientToken)` - Now available as a standalone method + +### Return Types + +The return types are now properly typed with TypeScript: + +```typescript +interface PaymentResult { + nonce: string; + type: string; + description: string; + isDefault: boolean; + deviceData: string; +} +``` + +## Compatibility + +### React Native Version Support + +- **Old**: React Native 0.60+ +- **New**: React Native 0.68+ (Turbo Modules support) + +If you're on an older React Native version, you'll need to upgrade first. + +### New Architecture + +The new package supports both: +- Old Architecture (Bridge) +- New Architecture (Turbo Modules) + +Enable New Architecture by setting: +- iOS: `ENV['RCT_NEW_ARCH_ENABLED'] = '1'` in Podfile +- Android: `newArchEnabled=true` in gradle.properties + +## Common Migration Issues + +### Issue 1: MainActivity Compilation Error + +**Error:** "MainActivity must extend FragmentActivity" + +**Solution:** +```kotlin +// Change from +class MainActivity : ReactActivity() + +// To +class MainActivity : FragmentActivity() +``` + +### Issue 2: Swift Bridging Header + +**Error:** "No such module 'BraintreeDropIn'" + +**Solution:** +1. Clean and rebuild +2. Check Swift version is 5.0+ +3. Run `pod install` again + +### Issue 3: Android Build Failures + +**Error:** Various Gradle errors + +**Solution:** +```bash +cd android +./gradlew clean +cd .. +# Rebuild +``` + +### Issue 4: Type Errors + +**Error:** TypeScript type mismatches + +**Solution:** Make sure you're importing types: +```typescript +import type { DropInOptions, PaymentResult } from 'react-native-braintree-dropin-turbo'; +``` + +## Testing After Migration + +Create a test checklist: + +- [ ] Drop-In UI displays correctly +- [ ] Card payment works +- [ ] Apple Pay works (iOS) +- [ ] Google Pay works (Android) +- [ ] Venmo works +- [ ] PayPal works +- [ ] 3D Secure verification works +- [ ] Error handling works +- [ ] Device data collection works +- [ ] Vault manager works (if used) + +## Rollback Plan + +If you need to rollback: + +```bash +# Uninstall new package +npm uninstall react-native-braintree-dropin-turbo + +# Reinstall old package +npm install react-native-braintree-dropin@[old-version] + +# Clean iOS +cd ios && rm -rf Pods Podfile.lock && pod install && cd .. + +# Revert MainActivity changes +# Rebuild +``` + +## Benefits of Migration + +1. ✅ **Performance**: Turbo Modules are faster than the old bridge +2. ✅ **Latest SDKs**: Access to latest Braintree features and security updates +3. ✅ **Type Safety**: Full TypeScript support +4. ✅ **Future-proof**: Compatible with React Native's New Architecture +5. ✅ **Better Maintenance**: Modern codebase with Swift and Kotlin +6. ✅ **Improved Error Handling**: Better error messages and handling + +## Getting Help + +If you encounter issues during migration: + +1. Check this migration guide +2. Review the [Installation Guide](./INSTALLATION.md) +3. Check closed issues on GitHub +4. Open a new issue with: + - Old package version + - New package version + - React Native version + - Complete error messages + - Migration steps attempted + +## Timeline Recommendation + +- **Testing Phase**: 1-2 days +- **Migration**: 2-3 hours +- **QA Testing**: 1-2 days +- **Monitoring**: 1 week post-release + +Good luck with your migration! 🚀 diff --git a/README.md b/README.md new file mode 100644 index 0000000..6571dd2 --- /dev/null +++ b/README.md @@ -0,0 +1,269 @@ +# react-native-braintree-dropin-turbo + +Modern Braintree Drop-In UI for React Native with Turbo Modules support. + +## Features + +- ✅ Turbo Modules support (React Native 0.68+) +- ✅ Latest Braintree SDK versions +- ✅ iOS (Swift) and Android (Kotlin) +- ✅ Apple Pay support (iOS) +- ✅ Google Pay support (Android) +- ✅ Venmo support +- ✅ PayPal support +- ✅ 3D Secure support +- ✅ Card tokenization +- ✅ Device data collection + +## Installation + +```bash +npm install react-native-braintree-dropin-turbo +# or +yarn add react-native-braintree-dropin-turbo +``` + +### iOS Setup + +1. Install pods: + +```bash +cd ios && pod install +``` + +2. Add to your `Info.plist` for Apple Pay: + +```xml +com.apple.developer.in-app-payments + + merchant.your.merchant.identifier + +``` + +### Android Setup + +1. Initialize DropIn client in your `MainActivity.kt`: + +```kotlin +import com.braintreedroptinturbo.RNBraintreeDropInModule + +class MainActivity : ReactActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + RNBraintreeDropInModule.initDropInClient(this) + } +} +``` + +2. Make sure your MainActivity extends `FragmentActivity`: + +```kotlin +import androidx.fragment.app.FragmentActivity + +class MainActivity : FragmentActivity() { + // ... +} +``` + +## Usage + +### Basic Usage + +```typescript +import BraintreeDropIn from 'react-native-braintree-dropin-turbo'; + +try { + const result = await BraintreeDropIn.show({ + clientToken: 'YOUR_CLIENT_TOKEN', + orderTotal: 10.0, + currencyCode: 'USD', + }); + + console.log('Payment nonce:', result.nonce); + console.log('Device data:', result.deviceData); + // Send result.nonce to your server +} catch (error) { + if (error.message === 'USER_CANCELLATION') { + console.log('User cancelled payment'); + } else { + console.error('Payment error:', error); + } +} +``` + +### With Apple Pay (iOS) + +```typescript +const result = await BraintreeDropIn.show({ + clientToken: 'YOUR_CLIENT_TOKEN', + applePay: true, + merchantIdentifier: 'merchant.your.identifier', + countryCode: 'US', + currencyCode: 'USD', + merchantName: 'Your Store', + orderTotal: 10.0, +}); +``` + +### With Google Pay (Android) + +```typescript +const result = await BraintreeDropIn.show({ + clientToken: 'YOUR_CLIENT_TOKEN', + googlePay: true, + googlePayMerchantId: 'YOUR_MERCHANT_ID', + orderTotal: 10.0, + currencyCode: 'USD', +}); +``` + +### With 3D Secure + +```typescript +const result = await BraintreeDropIn.show({ + clientToken: 'YOUR_CLIENT_TOKEN', + threeDSecure: { + amount: 10.0, + }, +}); +``` + +### Tokenize Card Directly + +```typescript +const result = await BraintreeDropIn.tokenizeCard('YOUR_CLIENT_TOKEN', { + number: '4111111111111111', + expirationMonth: '12', + expirationYear: '2025', + cvv: '123', + postalCode: '12345', +}); +``` + +### Collect Device Data + +```typescript +const deviceData = await BraintreeDropIn.collectDeviceData('YOUR_CLIENT_TOKEN'); +// Send to your server for fraud detection +``` + +### Fetch Most Recent Payment Method + +```typescript +const paymentMethod = + await BraintreeDropIn.fetchMostRecentPaymentMethod('YOUR_CLIENT_TOKEN'); + +if (paymentMethod) { + console.log('Last payment:', paymentMethod.description); +} +``` + +## API Reference + +### `show(options: DropInOptions): Promise` + +Display the Braintree Drop-In UI. + +#### Options + +| Option | Type | Required | Description | +| --------------------- | ------- | -------- | ---------------------------------------------------- | +| `clientToken` | string | ✅ | Braintree client token | +| `orderTotal` | number | ❌ | Total amount for the transaction | +| `currencyCode` | string | ❌ | Currency code (default: 'USD') | +| `darkTheme` | boolean | ❌ | Use dark theme (iOS only) | +| `fontFamily` | string | ❌ | Custom font family (iOS only) | +| `boldFontFamily` | string | ❌ | Custom bold font family (iOS only) | +| `vaultManager` | boolean | ❌ | Enable vault manager | +| `cardDisabled` | boolean | ❌ | Disable card payments | +| `applePay` | boolean | ❌ | Enable Apple Pay (iOS only) | +| `merchantIdentifier` | string | ❌ | Apple Pay merchant ID (required if applePay is true) | +| `countryCode` | string | ❌ | Country code for Apple Pay | +| `merchantName` | string | ❌ | Merchant name for Apple Pay | +| `venmo` | boolean | ❌ | Enable Venmo | +| `payPal` | boolean | ❌ | Enable PayPal | +| `googlePay` | boolean | ❌ | Enable Google Pay (Android only) | +| `googlePayMerchantId` | string | ❌ | Google Pay merchant ID | +| `threeDSecure` | object | ❌ | 3D Secure configuration | +| `threeDSecure.amount` | number | ❌ | Amount for 3D Secure verification | + +#### Returns + +```typescript +interface PaymentResult { + nonce: string; // Payment method nonce + type: string; // Payment method type + description: string; // Payment method description + isDefault: boolean; // Is default payment method + deviceData: string; // Device data for fraud detection +} +``` + +### `tokenizeCard(clientToken: string, cardInfo: CardInfo): Promise` + +Tokenize a card without showing the UI. + +```typescript +interface CardInfo { + number?: string; + expirationMonth?: string; + expirationYear?: string; + cvv: string; + postalCode?: string; + onlyCVV?: boolean; // If true, only CVV is required +} +``` + +### `collectDeviceData(clientToken: string): Promise` + +Collect device data for fraud detection. + +### `fetchMostRecentPaymentMethod(clientToken: string): Promise` + +Fetch the most recently used payment method. + +## Error Handling + +```typescript +try { + const result = await BraintreeDropIn.show(options); +} catch (error) { + switch (error.message) { + case 'USER_CANCELLATION': + // User cancelled the payment flow + break; + case 'NO_CLIENT_TOKEN': + // Client token was not provided + break; + case '3DSECURE_NOT_ABLE_TO_SHIFT_LIABILITY': + // 3D Secure verification failed + break; + default: + // Other errors + console.error(error); + } +} +``` + +## Braintree SDK Versions + +- **iOS**: Braintree ~> 6.0, BraintreeDropIn ~> 9.0 +- **Android**: Drop-In 6.16.0, Card 4.45.0, Data Collector 4.45.0 + +## Requirements + +- React Native >= 0.68 +- iOS >= 13.0 +- Android minSdkVersion >= 21 + +## New Architecture (Turbo Modules) + +This library supports the New Architecture out of the box. No additional configuration needed. + +## License + +MIT + +## Support + +For issues and feature requests, please visit the [GitHub repository](https://github.com/aveekshan/react-native-braintree-dropin-turbo). diff --git a/react-native-braintree-dropin-turbo.podspec b/react-native-braintree-dropin-turbo.podspec new file mode 100644 index 0000000..e840bb6 --- /dev/null +++ b/react-native-braintree-dropin-turbo.podspec @@ -0,0 +1,49 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "react-native-braintree-dropin-turbo" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => "13.0" } + s.source = { :git => "https://github.com/aveekshan/react-native-braintree-dropin-turbo.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. + # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79. + if respond_to?(:install_modules_dependencies, true) + install_modules_dependencies(s) + else + s.dependency "React-Core" + + # Don't install the dependencies when we run `pod install` in the old architecture. + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then + s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end + end + + # Braintree Dependencies + # s.dependency 'Braintree', '~> 6.0' + # s.dependency 'BraintreeDropIn', '~> 9.0' + # s.dependency 'Braintree/DataCollector', '~> 6.0' + # s.dependency 'Braintree/ApplePay', '~> 6.0' + # s.dependency 'Braintree/Venmo', '~> 6.0' + + s.swift_version = '5.0' +end