Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# CHANGELOG

## 6.2.0

### Features

- **OpenIAP Compliance**: Added `id` field to `Purchase` class for standardized transaction identification
- **Unified Purchase Token**: Added `purchaseToken` field for cross-platform server validation
- iOS: Contains JWS representation for App Store validation
- Android: Contains purchase token for Google Play validation
- Deprecated platform-specific token fields in favor of unified approach

### Improvements

- **Transaction Management**: `finishTransaction` now accepts `Purchase` objects directly
- **iOS StoreKit 2**: Complete implementation with improved transaction handling
- **Date Handling**: Fixed date parsing issues across platforms
- **Error Handling**: Enhanced error reporting and duplicate event prevention

### Bug Fixes

- Fixed missing `transactionId` and `id` fields in Android purchase responses
- Fixed iOS transaction finishing with proper ID lookup
- Fixed date conversion issues in `Purchase.fromJson()`

### Breaking Changes

None - This version maintains backward compatibility.

## 6.1.0

### Breaking Changes
Expand Down
14 changes: 10 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@

### Pre-Commit Checks

Before committing any changes:
Before committing any changes, run these commands in order and ensure ALL pass:

1. Run `dart format .` to ensure consistent code formatting
2. Run `flutter test` to verify all tests pass
3. Only commit if both checks succeed
1. **Format check**: `dart format --set-exit-if-changed .`
- This will fail if any files need formatting (exit code 1)
- If it fails, run `dart format .` to fix formatting, then retry
2. **Test validation**: `flutter test`
- All tests must pass
3. **Final verification**: Re-run `dart format --set-exit-if-changed .` to confirm no formatting issues
4. Only commit if ALL checks succeed with exit code 0

**Important**: Use `--set-exit-if-changed` flag to match CI behavior and catch formatting issues locally before they cause CI failures.

### Platform-Specific Naming Conventions

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

```yaml
dependencies:
flutter_inapp_purchase: ^6.1.0
flutter_inapp_purchase: ^6.2.0
```

## 🔧 Quick Start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler,
item.put("transactionId", purchase.orderId)
item.put("transactionDate", purchase.purchaseTime)
item.put("transactionReceipt", purchase.originalJson)
item.put("purchaseToken", purchase.purchaseToken)
item.put("purchaseToken", purchase.purchaseToken) // Unified field
item.put("purchaseTokenAndroid", purchase.purchaseToken) // Deprecated - use purchaseToken
item.put("signatureAndroid", purchase.signature)
item.put("purchaseStateAndroid", purchase.purchaseState)
if (type == BillingClient.ProductType.INAPP) {
Expand Down Expand Up @@ -344,10 +345,13 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler,
try {
for (purchase in purchasesList) {
val item = JSONObject()
item.put("id", purchase.orderId)
item.put("productId", purchase.products[0])
item.put("transactionId", purchase.orderId)
item.put("transactionDate", purchase.purchaseTime)
item.put("transactionReceipt", purchase.originalJson)
item.put("purchaseToken", purchase.purchaseToken)
item.put("purchaseToken", purchase.purchaseToken) // Unified field
item.put("purchaseTokenAndroid", purchase.purchaseToken) // Deprecated - use purchaseToken
item.put("dataAndroid", purchase.originalJson)
item.put("signatureAndroid", purchase.signature)
items.put(item)
Expand Down Expand Up @@ -489,8 +493,22 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler,
}
if (selectedProductDetails == null) {
val debugMessage =
"The selected product was not found. Please fetch setObfuscatedAccountIdproducts first by calling getItems"
safeChannel.error(TAG, "buyItemByType", debugMessage)
"The selected product was not found. Please fetch products first by calling getItems"

// Send purchase-error event like expo-iap
try {
val errorJson = JSONObject()
errorJson.put("code", "E_PRODUCT_NOT_FOUND")
errorJson.put("message", debugMessage)
errorJson.put("productId", productId)

Log.d(TAG, "Sending purchase-error event for product not found")
channel?.invokeMethod("purchase-error", errorJson.toString())
} catch (je: JSONException) {
Log.e(TAG, "Failed to create error JSON: ${je.message}")
}

safeChannel.error(TAG, "E_PRODUCT_NOT_FOUND", debugMessage)
return
}

Expand Down Expand Up @@ -572,6 +590,22 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler,
if (responseCode.responseCode != BillingClient.BillingResponseCode.OK) {
Log.e(TAG, "launchBillingFlow failed with code: ${responseCode.responseCode}, message: ${responseCode.debugMessage}")
val errorData = BillingError.getErrorFromResponseData(responseCode.responseCode)

// Send purchase-error event like expo-iap
try {
val errorJson = JSONObject()
errorJson.put("responseCode", responseCode.responseCode)
errorJson.put("debugMessage", responseCode.debugMessage)
errorJson.put("code", errorData.code)
errorJson.put("message", errorData.message)
errorJson.put("productId", productId)

Log.d(TAG, "Sending purchase-error event for launchBillingFlow failure")
channel?.invokeMethod("purchase-error", errorJson.toString())
} catch (je: JSONException) {
Log.e(TAG, "Failed to create error JSON: ${je.message}")
}

safeChannel.error(TAG, errorData.code, "Failed to launch billing flow: ${errorData.message}")
} else {
// Return success immediately - purchase result will come via purchasesUpdatedListener
Expand Down Expand Up @@ -621,7 +655,8 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler,
item.put("transactionId", purchase.orderId)
item.put("transactionDate", purchase.purchaseTime)
item.put("transactionReceipt", purchase.originalJson)
item.put("purchaseToken", purchase.purchaseToken)
item.put("purchaseToken", purchase.purchaseToken) // Unified field for iOS JWS and Android purchaseToken
item.put("purchaseTokenAndroid", purchase.purchaseToken) // Deprecated - use purchaseToken
item.put("dataAndroid", purchase.originalJson)
item.put("signatureAndroid", purchase.signature)
item.put("purchaseStateAndroid", purchase.purchaseState)
Expand Down
Empty file removed darwin/Assets/.gitkeep
Empty file.
Loading