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.


