getting function imported correctly in android but in ios gettting import value is null in react native module

30 views Asked by At

While building this react-native module, i'm getting the function imported correctly in android and i'm able to get the result correctly but in ios when i log the default import i get null.

App.tsx (when used the rn-module in an example app)

import UniqueIdentifier from 'rn-unique-identifier/js/NativeUniqueIdentifier'
...
console.log("UniqueIdentifier", UniqueIdentifier)
console.log("UID", UniqueIdentifier?.getPersistentIdentifier())
...

Logs on Android:

LOG  Running "z" with {"rootTag":1,"initialProps":{"concurrentRoot":true},"fabric":true}
LOG  UniqueIdentifier {"getPersistentIdentifier": [Function getPersistentIdentifier]}
LOG  UID 82e8380c4fe6fc40922cd890f8388419eaf41ef63f12027cafed64ab8f129d0b

Logs on Ios:

LOG  Running "z" with {"rootTag":1,"initialProps":{"concurrentRoot":true},"fabric":true}
LOG  UniqueIdentifier null
LOG  UID undefined

NativeUniqueIdentifier.ts

import {TurboModule, TurboModuleRegistry} from 'react-native'

export interface Spec extends TurboModule {
    getPersistentIdentifier(): string
}

export default TurboModuleRegistry.get<Spec>('UniqueIdentifier') as Spec | null

RTNUniqueIdentifier.h

#import <RTNUniqueIdentifierSpec/RTNUniqueIdentifierSpec.h>

NS_ASSUME_NONNULL_BEGIN

@interface RTNUniqueIdentifier : NSObject <NativeUniqueIdentifierSpec>

@end

NS_ASSUME_NONNULL_END

RTNUniqueIdentifier.mm

#import "RTNUniqueIdentifierSpec.h"
#import "RTNUniqueIdentifier.h"
#import "Security/Security.h"
#import "UIKit/UIKit.h"

@implementation RTNUniqueIdentifier

RCT_EXPORT_MODULE()
- (NSString *)getPersistentIdentifier {
    NSDictionary *keychainQuery = @{
        (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
        (__bridge id)kSecAttrService: @"MyAppDeviceId",
        (__bridge id)kSecReturnData: @YES
    };
    
    CFTypeRef keychainResult = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, &keychainResult);
    
    if (status == errSecSuccess) {
        // Device ID found in Keychain, return it
        NSData *keychainData = (__bridge_transfer NSData *)keychainResult;
        NSString *deviceId = [[NSString alloc] initWithData:keychainData encoding:NSUTF8StringEncoding];
        return deviceId;
    } else {
        // Device ID not found, generate a new one and store it in Keychain
        NSString *deviceId = [UIDevice currentDevice].identifierForVendor.UUIDString;
        
        if (!deviceId) {
            return nil;
        }
        
        NSData *deviceIdData = [deviceId dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *addQuery = @{
            (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
            (__bridge id)kSecAttrService: @"MyAppDeviceId",
            (__bridge id)kSecValueData: deviceIdData
        };
        
        OSStatus addStatus = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
        if (addStatus == errSecSuccess) {
            return deviceId;
        } else {
            return nil;
        }
    }
}


- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return std::make_shared<facebook::react::NativeUniqueIdentifierSpecJSI>(params);
}

@end

package.json

{
  "name": "rn-unique-identifier",
  "version": "1.0.1",
  "description": "Get persistent unique identifier in android & ios both",
  "react-native": "js/index",
  "source": "js/index",
  "files": [
    "js",
    "android",
    "ios",
    "unique-identifier.podspec",
    "!android/build",
    "!ios/build",
    "!**/__tests__",
    "!**/__fixtures__",
    "!**/__mocks__"
  ],
  "keywords": [
    "react-native",
    "ios",
    "android"
  ],
  "repository": "https://github.com/imtheaman/rn-unique-identifier.git",
  "author": "Aman Kumar <[email protected]>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/imtheaman/rn-unique-identifier/issues"
  },
  "homepage": "https://github.com/imtheaman/rn-unique-identifier#readme",
  "devDependencies": {},
  "peerDependencies": {
    "react": "*",
    "react-native": "*"
  },
  "codegenConfig": {
    "name": "RTNUniqueIdentifierSpec",
    "type": "modules",
    "jsSrcsDir": "js",
    "android": {
      "javaPackageName": "pkg.uniqueidentifier"
    }
  }
}

rn-unique-identifier.podspec

require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))

Pod::Spec.new do |s|
  s.name            = "rn-unique-identifier"
  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

UniqueIdentifierModule.java

package pkg.uniqueidentifier;

import androidx.annotation.NonNull;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import pkg.uniqueidentifier.NativeUniqueIdentifierSpec;
import android.media.MediaDrm;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

public class UniqueIdentifierModule extends NativeUniqueIdentifierSpec {

    public static String NAME = "UniqueIdentifier";

    UniqueIdentifierModule(ReactApplicationContext context) {
        super(context);
    }

    @Override
    @NonNull
    public String getName() {
        return NAME;
    }

    @Override
    public String getPersistentIdentifier() {
        UUID WIDEVINE_UUID = new UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L);
        MediaDrm wvDrm = null;

        try {
            wvDrm = new MediaDrm(WIDEVINE_UUID);
            byte[] widevineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID);
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(widevineId);
            return bytesToHexString(md.digest());
        } catch (Exception e) {
            return null;
        } finally {
            if (wvDrm != null) {
                wvDrm.close();
            }
        }
    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte aByte : bytes) {
            String hex = Integer.toHexString(0xFF & aByte);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

UniqueIdentifierPackage.java

package pkg.uniqueidentifier;

import androidx.annotation.Nullable;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.TurboReactPackage;

import java.util.Collections;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

public class UniqueIdentifierPackage extends TurboReactPackage {

  @Nullable
  @Override
  public NativeModule getModule(String name, ReactApplicationContext reactContext) {
      if (name.equals(UniqueIdentifierModule.NAME)) {
          return new UniqueIdentifierModule(reactContext);
      } else {
          return null;
      }
  }


  @Override
  public ReactModuleInfoProvider getReactModuleInfoProvider() {
      return () -> {
          final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
          moduleInfos.put(
                  UniqueIdentifierModule.NAME,
                  new ReactModuleInfo(
                          UniqueIdentifierModule.NAME,
                          UniqueIdentifierModule.NAME,
                          false, // canOverrideExistingModule
                          false, // needsEagerInit
                          true, // hasConstants
                          false, // isCxxModule
                          true // isTurboModule
          ));
          return moduleInfos;
      };
  }
}

folder structure:

├── android
│   ├── build.gradle
│   └── src
│       └── main
│           └── java
│               └── pkg
│                   └── uniqueidentifier
│                       ├── UniqueIdentifierModule.java
│                       └── UniqueIdentifierPackage.java
├── ios
│   ├── RTNUniqueIdentifier.h
│   └── RTNUniqueIdentifier.mm
├── js
│   ├── NativeUniqueIdentifier.ts
│   └── index.ts
├── node_modules
├── package.json
└── rn-unique-identifier.podspec

I tried searching the internet and raised issues in react-native repo discussion, but no luck.

0

There are 0 answers