Skip to content
Closed
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
13 changes: 13 additions & 0 deletions purchasely/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## Unreleased

### Added

- Added `PLYDataProcessingPurpose.refundHandling` for iOS (requires Purchasely
iOS 6.2.0). It carries the revoked refund-handling consent flag to the
backend.

### Fixed

- On iOS, combining `allNonEssentials` with other data processing purposes no
longer collapses the additional purposes.

## 6.1.0

Brings the Flutter plugin to Purchasely 6.1.0: the anonymous user id, the API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1557,20 +1557,18 @@ public class SwiftPurchaselyFlutterPlugin: NSObject, FlutterPlugin {
guard let arguments, let purposesArg = arguments["purposes"] as? [String] else {
return
}
let purposes: Set<PLYDataProcessingPurpose> = if purposesArg.contains("ALL_NON_ESSENTIALS") {
Set([PLYDataProcessingPurpose.allNonEssentials])
} else {
Set(purposesArg.compactMap { (value: String) -> PLYDataProcessingPurpose? in
switch value {
case "ANALYTICS": .analytics
case "IDENTIFIED_ANALYTICS": .identifiedAnalytics
case "CAMPAIGNS": .campaigns
case "PERSONALIZATION": .personalization
case "THIRD_PARTY_INTEGRATIONS": .thirdPartyIntegrations
default: nil
}
})
}
let purposes: Set<PLYDataProcessingPurpose> = Set(purposesArg.compactMap { (value: String) -> PLYDataProcessingPurpose? in
switch value {
case "ALL_NON_ESSENTIALS": .allNonEssentials
case "ANALYTICS": .analytics
case "IDENTIFIED_ANALYTICS": .identifiedAnalytics
case "CAMPAIGNS": .campaigns
case "PERSONALIZATION": .personalization
case "THIRD_PARTY_INTEGRATIONS": .thirdPartyIntegrations
case "REFUND_HANDLING": .refundHandling
default: nil
}
})
Purchasely.revokeDataProcessingConsent(for: purposes)
}

Expand Down
16 changes: 15 additions & 1 deletion purchasely/lib/purchasely_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,12 @@ class Purchasely {
_channel.invokeMethod('clearDynamicOfferings');
}

/// Replaces the persisted set of revoked purposes; it does not merge.
///
/// Pass the complete list every time. Passing `[]` grants everything back.
/// `allNonEssentials` is analytics, campaigns, personalization, and
/// thirdPartyIntegrations; it excludes identifiedAnalytics and refundHandling,
/// which must be combined explicitly when needed.
static void revokeDataProcessingConsent(
List<PLYDataProcessingPurpose> purposes) {
List<String> mappedPurposes = purposes
Expand Down Expand Up @@ -949,6 +955,8 @@ class Purchasely {
return "PERSONALIZATION";
case PLYDataProcessingPurpose.thirdPartyIntegrations:
return "THIRD_PARTY_INTEGRATIONS";
case PLYDataProcessingPurpose.refundHandling:
return "REFUND_HANDLING";
}
}
}
Expand Down Expand Up @@ -1013,7 +1021,13 @@ enum PLYDataProcessingPurpose {
identifiedAnalytics,
campaigns,
personalization,
thirdPartyIntegrations
thirdPartyIntegrations,

/// iOS only (Purchasely iOS >= 6.2.0); ignored on Android. Carries the
/// revoked-consent flag as `refund-handling` in the
/// `X-PRIVACY-CONSENT-REVOKED-FEATURES` header for refusal of consumption
/// data processing attached to a refund request. Gates no SDK behaviour.
refundHandling
}

enum PLYThemeMode { light, dark, system }
Expand Down
1 change: 1 addition & 0 deletions purchasely/test/platform_channel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ void main() {
expect(PLYDataProcessingPurpose.campaigns.index, 3);
expect(PLYDataProcessingPurpose.personalization.index, 4);
expect(PLYDataProcessingPurpose.thirdPartyIntegrations.index, 5);
expect(PLYDataProcessingPurpose.refundHandling.index, 6);
});
});

Expand Down
28 changes: 28 additions & 0 deletions purchasely/test/purchasely_flutter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,29 @@ void main() {
expect(
methodCalls.first.arguments['purposes'], ['ANALYTICS', 'CAMPAIGNS']);
});

test('revokeDataProcessingConsent maps refundHandling', () {
Purchasely.revokeDataProcessingConsent(
[PLYDataProcessingPurpose.refundHandling]);

expect(methodCalls.first.arguments['purposes'], ['REFUND_HANDLING']);
});

test('revokeDataProcessingConsent preserves combined purposes', () {
Purchasely.revokeDataProcessingConsent([
PLYDataProcessingPurpose.allNonEssentials,
PLYDataProcessingPurpose.refundHandling
]);

expect(methodCalls.first.arguments['purposes'],
['ALL_NON_ESSENTIALS', 'REFUND_HANDLING']);
});

test('revokeDataProcessingConsent clears all purposes', () {
Purchasely.revokeDataProcessingConsent([]);

expect(methodCalls.first.arguments['purposes'], []);
});
});

group('Transformation Methods', () {
Expand Down Expand Up @@ -877,6 +900,10 @@ void main() {
Purchasely.mapDataProcessingPurposeToString(
PLYDataProcessingPurpose.thirdPartyIntegrations),
'THIRD_PARTY_INTEGRATIONS');
expect(
Purchasely.mapDataProcessingPurposeToString(
PLYDataProcessingPurpose.refundHandling),
'REFUND_HANDLING');
});
});

Expand Down Expand Up @@ -1239,6 +1266,7 @@ void main() {
expect(PLYDataProcessingPurpose.campaigns.index, 3);
expect(PLYDataProcessingPurpose.personalization.index, 4);
expect(PLYDataProcessingPurpose.thirdPartyIntegrations.index, 5);
expect(PLYDataProcessingPurpose.refundHandling.index, 6);
});

test('PLYUserAttributeSource has correct values', () {
Expand Down
Loading