Commit 27f2bb35 authored by Gant Laborde's avatar Gant Laborde Committed by GitHub

Merge pull request #58 from mehcode/master

Use persistent UID for iOS
parents f488690c a9517557
......@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
76E65CA41D4CA143009B7AF1 /* DeviceUID.m in Sources */ = {isa = PBXBuildFile; fileRef = 76E65CA31D4CA143009B7AF1 /* DeviceUID.m */; };
DA5891DC1BA9A9FC002B4DB2 /* RNDeviceInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DA5891DB1BA9A9FC002B4DB2 /* RNDeviceInfo.h */; };
DA5891DE1BA9A9FC002B4DB2 /* RNDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5891DD1BA9A9FC002B4DB2 /* RNDeviceInfo.m */; };
/* End PBXBuildFile section */
......@@ -25,6 +26,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
76E65CA21D4CA143009B7AF1 /* DeviceUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceUID.h; sourceTree = "<group>"; };
76E65CA31D4CA143009B7AF1 /* DeviceUID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceUID.m; sourceTree = "<group>"; };
DA5891D81BA9A9FC002B4DB2 /* libRNDeviceInfo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNDeviceInfo.a; sourceTree = BUILT_PRODUCTS_DIR; };
DA5891DB1BA9A9FC002B4DB2 /* RNDeviceInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNDeviceInfo.h; sourceTree = "<group>"; };
DA5891DD1BA9A9FC002B4DB2 /* RNDeviceInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNDeviceInfo.m; sourceTree = "<group>"; };
......@@ -60,6 +63,8 @@
DA5891DA1BA9A9FC002B4DB2 /* RNDeviceInfo */ = {
isa = PBXGroup;
children = (
76E65CA21D4CA143009B7AF1 /* DeviceUID.h */,
76E65CA31D4CA143009B7AF1 /* DeviceUID.m */,
DA5891DB1BA9A9FC002B4DB2 /* RNDeviceInfo.h */,
DA5891DD1BA9A9FC002B4DB2 /* RNDeviceInfo.m */,
);
......@@ -122,6 +127,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
76E65CA41D4CA143009B7AF1 /* DeviceUID.m in Sources */,
DA5891DE1BA9A9FC002B4DB2 /* RNDeviceInfo.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
......
#import <Foundation/Foundation.h>
@interface DeviceUID : NSObject
+ (NSString *)uid;
@end
// Initial work from:
// https://gist.github.com/miguelcma/e8f291e54b025815ca46
// Modified as the original version crashes.
#import "DeviceUID.h"
@import UIKit;
@interface DeviceUID ()
@property(nonatomic, strong, readonly) NSString *uidKey;
@property(nonatomic, strong, readonly) NSString *uid;
@end
@implementation DeviceUID
@synthesize uid = _uid;
#pragma mark - Public methods
+ (NSString *)uid {
return [[[DeviceUID alloc] initWithKey:@"deviceUID"] uid];
}
#pragma mark - Instance methods
- (id)initWithKey:(NSString *)key {
self = [super init];
if (self) {
_uidKey = key;
_uid = nil;
}
return self;
}
/*! Returns the Device UID.
The UID is obtained in a chain of fallbacks:
- Keychain
- NSUserDefaults
- Apple IFV (Identifier for Vendor)
- Generate a random UUID if everything else is unavailable
At last, the UID is persisted if needed to.
*/
- (NSString *)uid {
if (!_uid) _uid = [[self class] valueForKeychainKey:_uidKey service:_uidKey];
if (!_uid) _uid = [[self class] valueForUserDefaultsKey:_uidKey];
if (!_uid) _uid = [[self class] appleIFV];
if (!_uid) _uid = [[self class] randomUUID];
[self save];
return _uid;
}
/*! Persist UID to NSUserDefaults and Keychain, if not yet saved
*/
- (void)save {
if (![DeviceUID valueForUserDefaultsKey:_uidKey]) {
[DeviceUID setValue:_uid forUserDefaultsKey:_uidKey];
}
if (![DeviceUID valueForKeychainKey:_uidKey service:_uidKey]) {
[DeviceUID setValue:_uid forKeychainKey:_uidKey inService:_uidKey];
}
}
#pragma mark - Keychain methods
/*! Create as generic NSDictionary to be used to query and update Keychain items.
* param1
* param2
*/
+ (NSMutableDictionary *)keychainItemForKey:(NSString *)key service:(NSString *)service {
NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init];
keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
keychainItem[(__bridge id)kSecAttrAccount] = key;
keychainItem[(__bridge id)kSecAttrService] = service;
return keychainItem;
}
/*! Sets
* param1
* param2
*/
+ (OSStatus)setValue:(NSString *)value forKeychainKey:(NSString *)key inService:(NSString *)service {
NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding];
return SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL);
}
+ (NSString *)valueForKeychainKey:(NSString *)key service:(NSString *)service {
OSStatus status;
NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
CFDictionaryRef result = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainItem, (CFTypeRef *)&result);
if (status != noErr) {
return nil;
}
NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result;
NSData *data = resultDict[(__bridge id)kSecValueData];
if (!data) {
return nil;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
#pragma mark - NSUserDefaults methods
+ (BOOL)setValue:(NSString *)value forUserDefaultsKey:(NSString *)key {
[[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
return [[NSUserDefaults standardUserDefaults] synchronize];
}
+ (NSString *)valueForUserDefaultsKey:(NSString *)key {
return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}
#pragma mark - UID Generation methods
+ (NSString *)appleIFV {
if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {
// only available in iOS >= 6.0
return [[UIDevice currentDevice].identifierForVendor UUIDString];
}
return nil;
}
+ (NSString *)randomUUID {
if(NSClassFromString(@"NSUUID")) {
return [[NSUUID UUID] UUIDString];
}
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
CFRelease(uuidRef);
NSString *uuid = [((__bridge NSString *) cfuuid) copy];
CFRelease(cfuuid);
return uuid;
}
@end
......@@ -7,6 +7,7 @@
//
#import "RNDeviceInfo.h"
#import "DeviceUID.h"
@interface RNDeviceInfo()
......@@ -152,7 +153,7 @@ RCT_EXPORT_MODULE()
UIDevice *currentDevice = [UIDevice currentDevice];
NSUUID *identifierForVendor = [currentDevice identifierForVendor];
NSString *uniqueId = [identifierForVendor UUIDString];
NSString *uniqueId = [DeviceUID uid];
return @{
@"systemName": currentDevice.systemName,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment