├── LICENSE
├── README.md
├── package.json
├── plugin.xml
├── src
├── android
│ └── UniqueDeviceID.java
├── ios
│ ├── CDVUniqueDeviceID.h
│ ├── CDVUniqueDeviceID.m
│ ├── UICKeyChainStore.h
│ └── UICKeyChainStore.m
└── wp
│ └── UniqueDeviceID.cs
└── www
└── uniqueid.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Paldom
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | UniqueDeviceID
2 | ==============
3 |
4 | PhoneGap / Cordova unique device id (UUID) plugin for Android, iOS and Windows Phone 8. Remains the same after app uninstall.
5 |
6 | ## Installation
7 |
8 | Latest stable release: ```phonegap local plugin add cordova-plugin-uniquedeviceid```
9 | or ```cordova plugin add cordova-plugin-uniquedeviceid```
10 |
11 | Current state from git: ```phonegap local plugin add https://github.com/Paldom/UniqueDeviceID.git```
12 | or ```cordova plugin add https://github.com/Paldom/UniqueDeviceID.git```
13 |
14 | ## Installation - PhoneGap Build
15 |
16 | Add following to config.xml: ``````
17 |
18 | For older versions, use the following: ``````
19 | or ``````
20 |
21 | ## Supported Platforms
22 |
23 | - Android
24 | - iOS
25 | - Windows Phone 8
26 |
27 | ## Usage
28 |
29 | // Get UUID
30 | window.plugins.uniqueDeviceID.get(success, fail);
31 |
32 | Success callback function:
33 |
34 | function success(uuid)
35 | {
36 | console.log(uuid);
37 | };
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cordova-plugin-uniquedeviceid",
3 | "version": "1.3.1",
4 | "description": "PhoneGap / Cordova unique device id (UUID) plugin for Android, iOS and Windows Phone 8. Remains the same after app uninstall.",
5 | "cordova": {
6 | "id": "cordova-plugin-uniquedeviceid",
7 | "platforms": [
8 | "ios",
9 | "android",
10 | "wp8"
11 | ]
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/Paldom/UniqueDeviceID.git"
16 | },
17 | "keywords": [
18 | "phonegap",
19 | "cordova",
20 | "android",
21 | "ios",
22 | "wp",
23 | "Windows",
24 | "phone",
25 | "device",
26 | "id",
27 | "uuid",
28 | "unique"
29 | ],
30 | "engines": [
31 | {
32 | "name": "cordova",
33 | "version": ">=3.0.0"
34 | }
35 | ],
36 | "author": "Domonkos Pal (https://github.com/Paldom)",
37 | "license": "MIT",
38 | "bugs": {
39 | "url": "https://github.com/Paldom/UniqueDeviceID/issues"
40 | },
41 | "homepage": "https://github.com/Paldom/UniqueDeviceID#readme"
42 | }
43 |
--------------------------------------------------------------------------------
/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | UniqueDeviceID
9 |
10 |
11 | PhoneGap / Cordova unique device id (UUID) plugin for Android, iOS and Windows Phone 8. Remains the same after app uninstall.
12 |
13 | MIT
14 | phonegap,cordova,android,ios,wp,Windows,phone,device,id,uuid,unique
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/android/UniqueDeviceID.java:
--------------------------------------------------------------------------------
1 | package hu.dpal.phonegap.plugins;
2 |
3 | import org.apache.cordova.CallbackContext;
4 | import org.apache.cordova.CordovaPlugin;
5 | import org.apache.cordova.CordovaWebView;
6 | import org.json.JSONArray;
7 | import org.json.JSONException;
8 |
9 | import android.Manifest;
10 | import android.content.Context;
11 | import android.content.pm.PackageManager;
12 | import android.provider.Settings.Secure;
13 | import android.telephony.TelephonyManager;
14 | import android.util.Log;
15 |
16 | import java.lang.reflect.Method;
17 |
18 | public class UniqueDeviceID extends CordovaPlugin {
19 |
20 | public static final String TAG = "UniqueDeviceID";
21 | public CallbackContext callbackContext;
22 | public static final int REQUEST_READ_PHONE_STATE = 0;
23 |
24 | protected final static String permission = Manifest.permission.READ_PHONE_STATE;
25 |
26 | @Override
27 | public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
28 | this.callbackContext = callbackContext;
29 | try {
30 | if (action.equals("get")) {
31 | if(this.hasPermission(permission)){
32 | getDeviceId();
33 | }else{
34 | this.requestPermission(this, REQUEST_READ_PHONE_STATE, permission);
35 | }
36 | }else {
37 | this.callbackContext.error("Invalid action");
38 | return false;
39 | }
40 | }catch(Exception e ) {
41 | this.callbackContext.error("Exception occurred: ".concat(e.getMessage()));
42 | return false;
43 | }
44 | return true;
45 |
46 | }
47 |
48 | public void onRequestPermissionResult(int requestCode, String[] permissions,
49 | int[] grantResults) throws JSONException {
50 | if(requestCode == REQUEST_READ_PHONE_STATE){
51 | getDeviceId();
52 | }
53 | }
54 |
55 | protected void getDeviceId(){
56 | try {
57 | Context context = cordova.getActivity().getApplicationContext();
58 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
59 |
60 | String uuid;
61 | String androidID = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
62 | String deviceID = tm.getDeviceId();
63 | String simID = tm.getSimSerialNumber();
64 |
65 | if ("9774d56d682e549c".equals(androidID) || androidID == null) {
66 | androidID = "";
67 | }
68 |
69 | if (deviceID == null) {
70 | deviceID = "";
71 | }
72 |
73 | if (simID == null) {
74 | simID = "";
75 | }
76 |
77 | uuid = androidID + deviceID + simID;
78 | uuid = String.format("%32s", uuid).replace(' ', '0');
79 | uuid = uuid.substring(0, 32);
80 | uuid = uuid.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
81 |
82 | this.callbackContext.success(uuid);
83 | }catch(Exception e ) {
84 | this.callbackContext.error("Exception occurred: ".concat(e.getMessage()));
85 | }
86 | }
87 |
88 | private boolean hasPermission(String permission) throws Exception{
89 | boolean hasPermission = true;
90 | Method method = null;
91 | try {
92 | method = cordova.getClass().getMethod("hasPermission", permission.getClass());
93 | Boolean bool = (Boolean) method.invoke(cordova, permission);
94 | hasPermission = bool.booleanValue();
95 | } catch (NoSuchMethodException e) {
96 | Log.w(TAG, "Cordova v" + CordovaWebView.CORDOVA_VERSION + " does not support API 23 runtime permissions so defaulting to GRANTED for " + permission);
97 | }
98 | return hasPermission;
99 | }
100 |
101 | private void requestPermission(CordovaPlugin plugin, int requestCode, String permission) throws Exception{
102 | try {
103 | java.lang.reflect.Method method = cordova.getClass().getMethod("requestPermission", org.apache.cordova.CordovaPlugin.class ,int.class, java.lang.String.class);
104 | method.invoke(cordova, plugin, requestCode, permission);
105 | } catch (NoSuchMethodException e) {
106 | throw new Exception("requestPermission() method not found in CordovaInterface implementation of Cordova v" + CordovaWebView.CORDOVA_VERSION);
107 | }
108 | }
109 | }
--------------------------------------------------------------------------------
/src/ios/CDVUniqueDeviceID.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDVUniqueDeviceID.h
3 | //
4 | //
5 | //
6 |
7 | #import
8 | #import
9 |
10 | @interface CDVUniqueDeviceID : CDVPlugin
11 |
12 | - (void)get:(CDVInvokedUrlCommand*)command;
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/src/ios/CDVUniqueDeviceID.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDVUniqueDeviceID.m
3 | //
4 | //
5 | //
6 |
7 | #import "CDVUniqueDeviceID.h"
8 | #import "UICKeyChainStore.h"
9 |
10 | @implementation CDVUniqueDeviceID
11 |
12 | -(void)get:(CDVInvokedUrlCommand*)command
13 | {
14 | [self.commandDelegate runInBackground:^{
15 |
16 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
17 | NSString *uuidUserDefaults = [defaults objectForKey:@"uuid"];
18 |
19 | NSString *uuid = [UICKeyChainStore stringForKey:@"uuid"];
20 |
21 | if ( uuid && !uuidUserDefaults) {
22 | [defaults setObject:uuid forKey:@"uuid"];
23 | [defaults synchronize];
24 |
25 | } else if ( !uuid && !uuidUserDefaults ) {
26 | NSString *uuidString = [[NSUUID UUID] UUIDString];
27 |
28 | [UICKeyChainStore setString:uuidString forKey:@"uuid"];
29 |
30 | [defaults setObject:uuidString forKey:@"uuid"];
31 | [defaults synchronize];
32 |
33 | uuid = [UICKeyChainStore stringForKey:@"uuid"];
34 |
35 | } else if ( ![uuid isEqualToString:uuidUserDefaults] ) {
36 | [UICKeyChainStore setString:uuidUserDefaults forKey:@"uuid"];
37 | uuid = [UICKeyChainStore stringForKey:@"uuid"];
38 | }
39 |
40 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:uuid];
41 | [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
42 | }];
43 | }
44 |
45 | @end
46 |
47 |
--------------------------------------------------------------------------------
/src/ios/UICKeyChainStore.h:
--------------------------------------------------------------------------------
1 | //
2 | // UICKeyChainStore.h
3 | // UICKeyChainStore
4 | //
5 | // Created by Kishikawa Katsumi on 11/11/20.
6 | // Copyright (c) 2011 Kishikawa Katsumi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UICKeyChainStore : NSObject
12 |
13 | @property (nonatomic, readonly) NSString *service;
14 | @property (nonatomic, readonly) NSString *accessGroup;
15 |
16 | + (NSString *)defaultService;
17 | + (void)setDefaultService:(NSString *)defaultService;
18 |
19 | + (UICKeyChainStore *)keyChainStore;
20 | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service;
21 | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup;
22 |
23 | - (instancetype)init;
24 | - (instancetype)initWithService:(NSString *)service;
25 | - (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup;
26 |
27 | + (NSString *)stringForKey:(NSString *)key;
28 | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service;
29 | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
30 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key;
31 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service;
32 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
33 |
34 | + (NSData *)dataForKey:(NSString *)key;
35 | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service;
36 | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
37 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key;
38 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service;
39 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
40 |
41 | - (void)setString:(NSString *)string forKey:(NSString *)key;
42 | - (NSString *)stringForKey:(NSString *)key;
43 |
44 | - (void)setData:(NSData *)data forKey:(NSString *)key;
45 | - (NSData *)dataForKey:(NSString *)key;
46 |
47 | + (BOOL)removeItemForKey:(NSString *)key;
48 | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service;
49 | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup;
50 | + (BOOL)removeAllItems;
51 | + (BOOL)removeAllItemsForService:(NSString *)service;
52 | + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup;
53 |
54 | - (void)removeItemForKey:(NSString *)key;
55 | - (void)removeAllItems;
56 |
57 | - (void)synchronize;
58 |
59 | // object subscripting
60 |
61 | - (NSString *)objectForKeyedSubscript:(NSString *)key;
62 | - (void)setObject:(NSString *)obj forKeyedSubscript:(NSString *)key;
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/src/ios/UICKeyChainStore.m:
--------------------------------------------------------------------------------
1 | //
2 | // UICKeyChainStore.m
3 | // UICKeyChainStore
4 | //
5 | // Created by Kishikawa Katsumi on 11/11/20.
6 | // Copyright (c) 2011 Kishikawa Katsumi. All rights reserved.
7 | //
8 |
9 | #import "UICKeyChainStore.h"
10 |
11 | static NSString *_defaultService;
12 |
13 | @interface UICKeyChainStore () {
14 | NSMutableDictionary *itemsToUpdate;
15 | }
16 |
17 | @end
18 |
19 | @implementation UICKeyChainStore
20 |
21 | + (NSString *)defaultService
22 | {
23 | if (!_defaultService) {
24 | _defaultService = [[NSBundle mainBundle] bundleIdentifier];
25 | }
26 |
27 | return _defaultService;
28 | }
29 |
30 | + (void)setDefaultService:(NSString *)defaultService
31 | {
32 | _defaultService = defaultService;
33 | }
34 |
35 | #pragma mark -
36 |
37 | + (UICKeyChainStore *)keyChainStore
38 | {
39 | return [[self alloc] initWithService:[self defaultService]];
40 | }
41 |
42 | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service
43 | {
44 | return [[self alloc] initWithService:service];
45 | }
46 |
47 | + (UICKeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup
48 | {
49 | return [[self alloc] initWithService:service accessGroup:accessGroup];
50 | }
51 |
52 | - (instancetype)init
53 | {
54 | return [self initWithService:[self.class defaultService] accessGroup:nil];
55 | }
56 |
57 | - (instancetype)initWithService:(NSString *)service
58 | {
59 | return [self initWithService:service accessGroup:nil];
60 | }
61 |
62 | - (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup
63 | {
64 | self = [super init];
65 | if (self) {
66 | if (!service) {
67 | service = [self.class defaultService];
68 | }
69 | _service = [service copy];
70 | _accessGroup = [accessGroup copy];
71 |
72 | itemsToUpdate = [[NSMutableDictionary alloc] init];
73 | }
74 |
75 | return self;
76 | }
77 |
78 | #pragma mark -
79 |
80 | + (NSString *)stringForKey:(NSString *)key
81 | {
82 | return [self stringForKey:key service:[self defaultService] accessGroup:nil];
83 | }
84 |
85 | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service
86 | {
87 | return [self stringForKey:key service:service accessGroup:nil];
88 | }
89 |
90 | + (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
91 | {
92 | NSData *data = [self dataForKey:key service:service accessGroup:accessGroup];
93 | if (data) {
94 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
95 | }
96 |
97 | return nil;
98 | }
99 |
100 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key
101 | {
102 | return [self setString:value forKey:key service:[self defaultService] accessGroup:nil];
103 | }
104 |
105 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service
106 | {
107 | return [self setString:value forKey:key service:service accessGroup:nil];
108 | }
109 |
110 | + (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
111 | {
112 | NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
113 | return [self setData:data forKey:key service:service accessGroup:accessGroup];
114 | }
115 |
116 | #pragma mark -
117 |
118 | + (NSData *)dataForKey:(NSString *)key
119 | {
120 | return [self dataForKey:key service:[self defaultService] accessGroup:nil];
121 | }
122 |
123 | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service
124 | {
125 | return [self dataForKey:key service:service accessGroup:nil];
126 | }
127 |
128 | + (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
129 | {
130 | if (!key) {
131 | return nil;
132 | }
133 | if (!service) {
134 | service = [self defaultService];
135 | }
136 |
137 | NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
138 | [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
139 | [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
140 | [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
141 | [query setObject:service forKey:(__bridge id)kSecAttrService];
142 | [query setObject:key forKey:(__bridge id)kSecAttrGeneric];
143 | [query setObject:key forKey:(__bridge id)kSecAttrAccount];
144 | #if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
145 | if (accessGroup) {
146 | [query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
147 | }
148 | #endif
149 |
150 | CFTypeRef data = nil;
151 | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &data);
152 | if (status != errSecSuccess) {
153 | return nil;
154 | }
155 |
156 | NSData *ret = [NSData dataWithData:(__bridge NSData *)data];
157 | if (data) {
158 | CFRelease(data);
159 | }
160 |
161 | return ret;
162 | }
163 |
164 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key
165 | {
166 | return [self setData:data forKey:key service:[self defaultService] accessGroup:nil];
167 | }
168 |
169 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service
170 | {
171 | return [self setData:data forKey:key service:service accessGroup:nil];
172 | }
173 |
174 | + (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
175 | {
176 | if (!key) {
177 | return NO;
178 | }
179 | if (!service) {
180 | service = [self defaultService];
181 | }
182 |
183 | NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
184 | [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
185 | [query setObject:service forKey:(__bridge id)kSecAttrService];
186 | [query setObject:key forKey:(__bridge id)kSecAttrGeneric];
187 | [query setObject:key forKey:(__bridge id)kSecAttrAccount];
188 | #if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
189 | if (accessGroup) {
190 | [query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
191 | }
192 | #endif
193 |
194 | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
195 | if (status == errSecSuccess) {
196 | if (data) {
197 | NSMutableDictionary *attributesToUpdate = [[NSMutableDictionary alloc] init];
198 | [attributesToUpdate setObject:data forKey:(__bridge id)kSecValueData];
199 |
200 | status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate);
201 | if (status != errSecSuccess) {
202 | return NO;
203 | }
204 | } else {
205 | [self removeItemForKey:key service:service accessGroup:accessGroup];
206 | }
207 | } else if (status == errSecItemNotFound) {
208 | NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
209 | [attributes setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
210 | [attributes setObject:service forKey:(__bridge id)kSecAttrService];
211 | [attributes setObject:key forKey:(__bridge id)kSecAttrGeneric];
212 | [attributes setObject:key forKey:(__bridge id)kSecAttrAccount];
213 | #if TARGET_OS_IPHONE || (defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)
214 | [attributes setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
215 | #endif
216 | [attributes setObject:data forKey:(__bridge id)kSecValueData];
217 | #if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
218 | if (accessGroup) {
219 | [attributes setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
220 | }
221 | #endif
222 |
223 | status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
224 | if (status != errSecSuccess) {
225 | return NO;
226 | }
227 | } else {
228 | return NO;
229 | }
230 |
231 | return YES;
232 | }
233 |
234 | #pragma mark -
235 |
236 | - (void)setString:(NSString *)string forKey:(NSString *)key
237 | {
238 | [self setData:[string dataUsingEncoding:NSUTF8StringEncoding] forKey:key];
239 | }
240 |
241 | - (NSString *)stringForKey:(id)key
242 | {
243 | NSData *data = [self dataForKey:key];
244 | if (data) {
245 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
246 | }
247 |
248 | return nil;
249 | }
250 |
251 | #pragma mark -
252 |
253 | - (void)setData:(NSData *)data forKey:(NSString *)key
254 | {
255 | if (!key) {
256 | return;
257 | }
258 | if (!data) {
259 | [self removeItemForKey:key];
260 | } else {
261 | [itemsToUpdate setObject:data forKey:key];
262 | }
263 | }
264 |
265 | - (NSData *)dataForKey:(NSString *)key
266 | {
267 | NSData *data = [itemsToUpdate objectForKey:key];
268 | if (!data) {
269 | data = [[self class] dataForKey:key service:self.service accessGroup:self.accessGroup];
270 | }
271 |
272 | return data;
273 | }
274 |
275 | #pragma mark -
276 |
277 | + (BOOL)removeItemForKey:(NSString *)key
278 | {
279 | return [UICKeyChainStore removeItemForKey:key service:[self defaultService] accessGroup:nil];
280 | }
281 |
282 | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service
283 | {
284 | return [UICKeyChainStore removeItemForKey:key service:service accessGroup:nil];
285 | }
286 |
287 | + (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup
288 | {
289 | if (!key) {
290 | return NO;
291 | }
292 | if (!service) {
293 | service = [self defaultService];
294 | }
295 |
296 | NSMutableDictionary *itemToDelete = [[NSMutableDictionary alloc] init];
297 | [itemToDelete setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
298 | [itemToDelete setObject:service forKey:(__bridge id)kSecAttrService];
299 | [itemToDelete setObject:key forKey:(__bridge id)kSecAttrGeneric];
300 | [itemToDelete setObject:key forKey:(__bridge id)kSecAttrAccount];
301 | #if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
302 | if (accessGroup) {
303 | [itemToDelete setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
304 | }
305 | #endif
306 |
307 | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)itemToDelete);
308 | if (status != errSecSuccess && status != errSecItemNotFound) {
309 | return NO;
310 | }
311 |
312 | return YES;
313 | }
314 |
315 | + (NSArray *)itemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
316 | {
317 | if (!service) {
318 | service = [self defaultService];
319 | }
320 |
321 | NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
322 | [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
323 | [query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
324 | [query setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
325 | [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
326 | [query setObject:service forKey:(__bridge id)kSecAttrService];
327 | #if !TARGET_IPHONE_SIMULATOR && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
328 | if (accessGroup) {
329 | [query setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
330 | }
331 | #endif
332 |
333 | CFArrayRef result = nil;
334 | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
335 | if (status == errSecSuccess || status == errSecItemNotFound) {
336 | return CFBridgingRelease(result);
337 | } else {
338 | return nil;
339 | }
340 | }
341 |
342 | + (BOOL)removeAllItems
343 | {
344 | return [self removeAllItemsForService:[self defaultService] accessGroup:nil];
345 | }
346 |
347 | + (BOOL)removeAllItemsForService:(NSString *)service
348 | {
349 | return [self removeAllItemsForService:service accessGroup:nil];
350 | }
351 |
352 | + (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup
353 | {
354 | NSArray *items = [UICKeyChainStore itemsForService:service accessGroup:accessGroup];
355 | for (NSDictionary *item in items) {
356 | NSMutableDictionary *itemToDelete = [[NSMutableDictionary alloc] initWithDictionary:item];
357 | [itemToDelete setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
358 |
359 | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)itemToDelete);
360 | if (status != errSecSuccess) {
361 | return NO;
362 | }
363 | }
364 |
365 | return YES;
366 | }
367 |
368 | #pragma mark -
369 |
370 | - (void)removeItemForKey:(NSString *)key
371 | {
372 | if ([itemsToUpdate objectForKey:key]) {
373 | [itemsToUpdate removeObjectForKey:key];
374 | } else {
375 | [[self class] removeItemForKey:key service:self.service accessGroup:self.accessGroup];
376 | }
377 | }
378 |
379 | - (void)removeAllItems
380 | {
381 | [itemsToUpdate removeAllObjects];
382 | [[self class] removeAllItemsForService:self.service accessGroup:self.accessGroup];
383 | }
384 |
385 | #pragma mark -
386 |
387 | - (void)synchronize
388 | {
389 | for (NSString *key in itemsToUpdate) {
390 | [[self class] setData:[itemsToUpdate objectForKey:key] forKey:key service:self.service accessGroup:self.accessGroup];
391 | }
392 |
393 | [itemsToUpdate removeAllObjects];
394 | }
395 |
396 | #pragma mark -
397 |
398 | - (NSString *)description
399 | {
400 | NSArray *items = [UICKeyChainStore itemsForService:self.service accessGroup:self.accessGroup];
401 | NSMutableArray *list = [[NSMutableArray alloc] initWithCapacity:items.count];
402 | for (NSDictionary *attributes in items) {
403 | NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
404 | [attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrService] forKey:@"Service"];
405 | [attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrAccount] forKey:@"Account"];
406 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
407 | [attrs setObject:[attributes objectForKey:(__bridge id)kSecAttrAccessGroup] forKey:@"AccessGroup"];
408 | #endif
409 | NSData *data = [attributes objectForKey:(__bridge id)kSecValueData];
410 | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
411 | if (string) {
412 | [attrs setObject:string forKey:@"Value"];
413 | } else {
414 | [attrs setObject:data forKey:@"Value"];
415 | }
416 | [list addObject:attrs];
417 | }
418 |
419 | return [list description];
420 | }
421 |
422 | #pragma mark - Object Subscripting
423 |
424 | - (NSString *)objectForKeyedSubscript:(NSString *)key
425 | {
426 | return [self stringForKey:key];
427 | }
428 |
429 | - (void)setObject:(NSString *)obj forKeyedSubscript:(NSString *)key
430 | {
431 | [self setString:obj forKey:key];
432 | }
433 |
434 | @end
435 |
--------------------------------------------------------------------------------
/src/wp/UniqueDeviceID.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.Phone.System.Analytics;
3 | using WPCordovaClassLib.Cordova;
4 | using WPCordovaClassLib.Cordova.Commands;
5 | using WPCordovaClassLib.Cordova.JSON;
6 |
7 | namespace WPCordovaClassLib.Cordova.Commands
8 | {
9 | public class UniqueDeviceID : BaseCommand
10 | {
11 | public void get(string options)
12 | {
13 |
14 | string uuid = Windows.Phone.System.Analytics.HostInformation.PublisherHostId;
15 | uuid = uuid.Substring(0, 32);
16 |
17 | DispatchCommandResult(new PluginResult(PluginResult.Status.OK, uuid));
18 |
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/www/uniqueid.js:
--------------------------------------------------------------------------------
1 | var exec = require('cordova/exec');
2 |
3 | module.exports = {
4 |
5 | get: function(success, fail) {
6 | cordova.exec(success, fail, 'UniqueDeviceID', 'get', []);
7 | }
8 |
9 | };
--------------------------------------------------------------------------------