TheWirv / react-native-wallet-passes

React Native module to handle Wallet passes on iOS and Android.
MIT License
10 stars 4 forks source link

feature: check if pass already exists in wallet #3

Open fiznool opened 2 years ago

fiznool commented 2 years ago

Hi! 👋

Just wanted to start by saying a huge thank you for taking on this package and modernising it with Typescript. Its really well written, and has almost(!) everything I need for my current project. ❤️

I have the need for an extra feature - checking if a pass already exists in the Wallet, according to the passTypeIdentifier. I used patch-package to patch react-native-wallet-passes@1.2.2 in order to add in this functionality on my current project, which is working nicely.

I've pasted the diff I'm using below, but I would be happy to package this up as a PR, if you feel it would be a useful addition?

diff --git a/android/src/main/java/com/thewirv/RNWalletPasses/RNWalletPassesModule.java b/android/src/main/java/com/thewirv/RNWalletPasses/RNWalletPassesModule.java
index 4ebc427..99f5a5c 100644
--- a/android/src/main/java/com/thewirv/RNWalletPasses/RNWalletPassesModule.java
+++ b/android/src/main/java/com/thewirv/RNWalletPasses/RNWalletPassesModule.java
@@ -62,6 +62,11 @@ public class RNWalletPassesModule extends ReactContextBaseJavaModule {
         }
     }

+    @ReactMethod
+    public void hasPassWithTypeIdentifier(String passTypeIdentifier, Promise promise) {
+        promise.reject(new JSApplicationCausedNativeException("hasPassWithTypeIdentifier is not available on Android"));
+    }
+
     @ReactMethod
     public void addPass(String encodedPassFile, String fileProvider, Promise promise) {
         try {
diff --git a/ios/RNWalletPasses/RNWalletPasses.m b/ios/RNWalletPasses/RNWalletPasses.m
index eba5692..96f1a16 100644
--- a/ios/RNWalletPasses/RNWalletPasses.m
+++ b/ios/RNWalletPasses/RNWalletPasses.m
@@ -22,6 +22,13 @@ RCT_EXPORT_METHOD(canAddPasses:(RCTPromiseResolveBlock)resolve
     resolve(@([PKAddPassesViewController canAddPasses]));
 }

+RCT_EXPORT_METHOD(hasPassWithTypeIdentifier:(NSString *)passTypeIdentifier
+                  resolver:(RCTPromiseResolveBlock)resolve
+                  rejector:(RCTPromiseRejectBlock)reject) {
+
+    resolve(@([self passAlreadyExistsWithTypeIdentifier:passTypeIdentifier]));
+}
+
 RCT_EXPORT_METHOD(addPass:(NSString *)base64Encoded
                   resolver:(RCTPromiseResolveBlock)resolve
                   rejector:(RCTPromiseRejectBlock)reject) {
@@ -34,6 +41,13 @@ RCT_EXPORT_METHOD(addPass:(NSString *)base64Encoded
         return;
     }

+    // Check if pass already exists: if so, don't try to add again
+    PKPassLibrary *passLibrary = [[PKPassLibrary alloc] init];
+    if([passLibrary containsPass:pass]) {
+        resolve(nil);
+        return;
+    }
+
     dispatch_async(dispatch_get_main_queue(), ^{
         UIViewController *rootViewController = [self getPresenterViewController];
         if (rootViewController) {
@@ -103,4 +117,15 @@ RCT_EXPORT_METHOD(addPass:(NSString *)base64Encoded
     return presentingViewcontroller;
 }

+-(BOOL)passAlreadyExistsWithTypeIdentifier:(NSString *)passTypeIdentifier {
+    PKPassLibrary *passLibrary = [[PKPassLibrary alloc] init];
+    NSArray<PKPass *> *existingPasses = [passLibrary passes];
+    for (PKPass *pass in existingPasses) {
+        if([[pass passTypeIdentifier] isEqualToString:passTypeIdentifier]) {
+            return YES;
+        }
+    }
+    return NO;
+}
+
 @end
diff --git a/lib/commonjs/WalletPasses.js b/lib/commonjs/WalletPasses.js
index 52ed261..a428b42 100644
--- a/lib/commonjs/WalletPasses.js
+++ b/lib/commonjs/WalletPasses.js
@@ -24,6 +24,20 @@ const WalletPasses = {
     return new Promise(resolve => resolve(false));
   },

+
+  /**
+   * Checks whether a pass with the provided `passIdentifierType` is already present in the Wallet. iOS only.
+   *
+   * @param passTypeIdentifier Pass type identifier, used to search for an existing pass in the Wallet
+   */
+   hasPassWithTypeIdentifier: (passTypeIdentifier) => {
+    if (_reactNative.Platform.OS === 'ios') {
+      return RNWalletPasses.hasPassWithTypeIdentifier(passTypeIdentifier);
+    }
+
+    return Promise.reject(new Error('Checking that a pass is already added to the Wallet is only supported on iOS.'))
+  },
+
   /**
    * Adds a pass to the Wallet.
    *
diff --git a/lib/module/WalletPasses.js b/lib/module/WalletPasses.js
index 1ccea93..60f9228 100644
--- a/lib/module/WalletPasses.js
+++ b/lib/module/WalletPasses.js
@@ -16,6 +16,19 @@ const WalletPasses = {
     return new Promise(resolve => resolve(false));
   },

+  /**
+   * Checks whether a pass with the provided `passIdentifierType` is already present in the Wallet. iOS only.
+   *
+   * @param passTypeIdentifier Pass type identifier, used to search for an existing pass in the Wallet
+   */
+   hasPassWithTypeIdentifier: (passTypeIdentifier) => {
+    if (Platform.OS === 'ios') {
+      return RNWalletPasses.hasPassWithTypeIdentifier(passTypeIdentifier);
+    }
+
+    return Promise.reject(new Error('Checking that a pass is already added to the Wallet is only supported on iOS.'))
+  },
+
   /**
    * Adds a pass to the Wallet.
    *
diff --git a/lib/typescript/WalletPasses.d.ts b/lib/typescript/WalletPasses.d.ts
index 3b16f78..2547c66 100644
--- a/lib/typescript/WalletPasses.d.ts
+++ b/lib/typescript/WalletPasses.d.ts
@@ -3,6 +3,12 @@ declare const WalletPasses: {
      * Checks whether Wallet passes can be added on this device.
      */
     canAddPasses: () => Promise<boolean>;
+    /**
+     * Checks whether a pass with the provided `passIdentifierType` is already present in the Wallet. iOS only.
+     *
+     * @param passTypeIdentifier Pass type identifier, used to search for an existing pass in the Wallet
+     */
+    hasPassWithTypeIdentifier: (passTypeIdentifier: string) => Promise<boolean>;
     /**
      * Adds a pass to the Wallet.
      *
diff --git a/src/WalletPasses.ts b/src/WalletPasses.ts
index 36c3aac..728c2b8 100644
--- a/src/WalletPasses.ts
+++ b/src/WalletPasses.ts
@@ -16,6 +16,19 @@ const WalletPasses = {
     return new Promise((resolve) => resolve(false));
   },

+  /**
+   * Checks whether a pass with the provided `passIdentifierType` is already present in the Wallet. iOS only.
+   *
+   * @param passTypeIdentifier Pass type identifier, used to search for an existing pass in the Wallet
+   */
+   hasPassWithTypeIdentifier: (passTypeIdentifier: string): Promise<boolean> => {
+    if (Platform.OS === 'ios') {
+      return RNWalletPasses.hasPassWithTypeIdentifier(passTypeIdentifier);
+    }
+
+    return Promise.reject(new Error('Checking that a pass is already added to the Wallet is only supported on iOS.'))
+  },
+
   /**
    * Adds a pass to the Wallet.
    *
pke commented 2 years ago

I wouldn't reject if this function is called from Android. Just return false and emit a warning to the console would make the handling of this new API much cleaner.

labmorales commented 1 year ago

Hey, @fiznool I think this would be a great addition to the plugin. Could you wrap this up in a PR?

fiznool commented 1 year ago

Hi @labmorales - I've moved on to another project and sadly don't have the time to create a PR, but if somebody else would like to do so instead, it would be a great addition to the library.