UIDevice uniqueIdentifier không dùng nữa - Phải làm gì bây giờ?


501

Nó đã được đưa ra ánh sáng rằng thuộc tính UIDevice uniqueIdentifier bị phản đối trong iOS 5 và không có sẵn trong iOS 7 trở lên. Không có phương pháp hoặc tài sản thay thế dường như có sẵn hoặc sắp tới.

Nhiều ứng dụng hiện có của chúng tôi phụ thuộc chặt chẽ vào tài sản này để nhận dạng duy nhất một thiết bị cụ thể. Làm thế nào chúng ta có thể xử lý vấn đề này trong tương lai?

Gợi ý từ tài liệu năm 2011-2012 là:

Cân nhắc đặc biệt

Không sử dụng thuộc tính uniqueIdentifier. Để tạo một mã định danh duy nhất dành riêng cho ứng dụng của bạn, bạn có thể gọi CFUUIDCreatehàm để tạo UUIDvà ghi nó vào cơ sở dữ liệu mặc định bằng cách sử dụng NSUserDefaultslớp.

Tuy nhiên, giá trị này sẽ không giống nhau nếu người dùng gỡ cài đặt và cài đặt lại ứng dụng.


1
Đối với các ứng dụng vẫn đang sử dụng uniqueIdentifier, iOS7 hiện trả về FFFFFFFF + định danhForVendor, thứ đang phá vỡ rất nhiều ứng dụng đăng ký không gia hạn được viết xấu.
Fistman nhịp điệu

Nếu may mắn, ứng dụng của bạn sử dụng Thông báo đẩy, bạn có thể sử dụng mã thông báo được gửi lại từ dịch vụ đẩy của apple, đó là duy nhất cho mỗi thiết bị
Calin Chitu

@CalinChitu Nếu người dùng không chấp nhận thông báo đẩy, bạn vẫn nhận được một PushID cho người dùng đó chứ?
Chase Roberts

Câu trả lời:


272

Một UUID được tạo bởi CFUUIDCreate duy nhất nếu người dùng gỡ cài đặt và cài đặt lại ứng dụng: bạn sẽ nhận được một cái mới mỗi lần.

Nhưng bạn có thể muốn nó không phải là duy nhất, tức là nó sẽ giữ nguyên khi người dùng gỡ cài đặt và cài đặt lại ứng dụng. Điều này đòi hỏi một chút nỗ lực, vì định danh trên mỗi thiết bị đáng tin cậy nhất dường như là địa chỉ MAC. Bạn có thể truy vấn MAC và sử dụng nó như UUID.

Chỉnh sửa: Tất nhiên, người ta cần luôn truy vấn MAC của cùng một giao diện. Tôi đoán đặt cược tốt nhất là với en0. MAC luôn có mặt, ngay cả khi giao diện không có IP / bị hỏng.

Chỉnh sửa 2: Như đã được chỉ ra bởi những người khác, giải pháp ưa thích kể từ iOS 6 là - [UIDevice định danhForVendor] . Trong hầu hết các trường hợp, bạn sẽ có thể sử dụng nó như một sự thay thế thả xuống so với cái cũ -[UIDevice uniqueIdentifier](nhưng một UUID được tạo khi ứng dụng khởi động lần đầu tiên là thứ mà Apple dường như muốn bạn sử dụng).

Chỉnh sửa 3: Vì vậy, điểm quan trọng này không bị mất trong tiếng ồn bình luận: không sử dụng MAC làm UUID, tạo băm bằng MAC . Băm đó sẽ luôn tạo ra kết quả giống nhau mọi lúc, ngay cả trên các cài đặt lại và ứng dụng (nếu việc băm được thực hiện theo cùng một cách). Dù sao, ngày nay (2013) điều này không còn cần thiết nữa trừ khi bạn cần số nhận dạng thiết bị "ổn định" trên iOS <6.0.

Chỉnh sửa 4: Trong iOS 7, Apple hiện luôn trả về một giá trị cố định khi truy vấn MAC để ngăn chặn cụ thể MAC làm cơ sở cho sơ đồ ID . Vì vậy, bây giờ bạn thực sự nên sử dụng - [UIDevice định danhForVendor] hoặc tạo UUID mỗi lần cài đặt.


8
Địa chỉ mac không thay đổi tùy thuộc vào việc người dùng có được kết nối qua Wifi hay không?
Oliver Pearmain

1
@DarkDust: nhưng vì giao diện hoạt động thay đổi khi bạn chuyển từ wifi sang modem di động, địa chỉ MAC của giao diện hoạt động cũng sẽ thay đổi; trừ khi bạn luôn chọn một giao diện cụ thể để nhận MAC
user102008

3
@Roger Nolan: Vui lòng không chỉnh sửa câu trả lời của người khác và thêm nội dung có vẻ như đến từ tác giả gốc. Cảm ơn.
DarkDust

2
@RogerNolan Miễn là bài đăng không phải là câu trả lời của cộng đồng, các chỉnh sửa là để sửa lỗi và những thứ như vậy, không phải để thêm nội dung mới. Có một lý do bạn đã kiếm được đặc quyền. Hãy tưởng tượng tôi chỉnh sửa câu trả lời của bạn và viết một số BS, mọi người sẽ nghĩ bạn sẽ viết nó. Tôi nghi ngờ bạn thích điều đó :-) Nhưng bạn không nhận được thông báo rằng một chỉnh sửa đã xảy ra, tôi chỉ tình cờ phát hiện ra.
DarkDust

3
Apple hiện từ chối các ứng dụng sử dụng MAC băm.
Idan

91

Bạn có thể sử dụng thay thế cho Apple UDIDrồi. Anh chàng tốt bụng đã viết thể loại trên UIDeviceđó sẽ tạo ra một số loại UDIDdựa trên địa chỉ mac của thiết bị và định danh gói.

Bạn có thể tìm mã trên github


3
Việc triển khai này là duy nhất (địa chỉ MAC) cho một thiết bị trong các lần cài đặt lại, như uniqueId của Apple, nhưng cũng tôn trọng quyền riêng tư, cũng là duy nhất cho một ứng dụng (cũng sử dụng bundleId) ... Apple phải đưa vào API của mình. .. thay vì phản đối w / o bất kỳ lựa chọn thay thế.
Vincent Guerci

8
Mặc dù nó sử dụng giấy phép bsd kiểu cũ với điều khoản quảng cáo, yuck.
jbtule

8
Đối với bất cứ ai khác bây giờ tìm thấy bài đăng này, giấy phép đã được thay đổi kể từ nhận xét trên của jbtule.
James

1
Như đã thảo luận trong nhận xét cam kết này, thư viện như đang đặt ra vấn đề rò rỉ quyền riêng tư nghiêm trọng và không nên được sử dụng:
Sẽ

15
Bắt đầu từ iOS 7, hệ thống luôn trả về giá trị 02:00:00:00:00:00khi bạn yêu cầu địa chỉ MAC trên bất kỳ thiết bị nào. Kiểm tra tại đây: developer.apple.com/l
Library / preselease / ios / releasenotes / General / từ

61

Dựa trên liên kết được đề xuất bởi @moonlight, tôi đã thực hiện một số thử nghiệm và nó dường như là giải pháp tốt nhất. Như @DarkDust nói rằng phương thức này sẽ kiểm tra en0cái luôn có sẵn.
Có 2 tùy chọn:
uniqueDeviceIdentifier(MD5 của MAC + CFBundleIdentifier)
uniqueGlobalDeviceIdentifier(MD5 của MAC), chúng luôn trả về cùng một giá trị.
Bên dưới các thử nghiệm tôi đã thực hiện (với thiết bị thực):

#import "UIDevice+IdentifierAddition.h"

NSLog(@"%@",[[UIDevice currentDevice] uniqueDeviceIdentifier]);
NSLog(@"%@",[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]);

XXXX21f1f19edff198e2a2356bf4XXXX - (WIFI) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (WIFI) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (3G) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (3G) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (GPRS) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (GPRS) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (chế độ AirPlane) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (chế độ AirPlane) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) sau khi gỡ bỏ và cài đặt lại ứng dụng XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) sau khi gỡ bỏ và cài đặt ứng dụng

Hy vọng nó hữu ích.

EDIT:
Như những người khác đã chỉ ra, giải pháp này trong iOS 7 không còn hữu ích vì uniqueIdentifierkhông còn khả dụng và truy vấn địa chỉ MAC bây giờ luôn trả về 02: 00: 00: 00: 00: 00


13
Điều này sẽ không hoạt động trên iOS7, Apple loại bỏ việc sử dụng địa chỉ MAC.
Sarim Sidd

@SarimSidd Hiện tại thông tin về iOS 7 thuộc NDA, chúng tôi không thể thảo luận ở đây.
Mat

57

kiểm tra này

chúng ta có thể sử dụng Keychain thay vì NSUserDefaultslớp, để lưu trữ UUIDđược tạo bởi CFUUIDCreate.

với cách này, chúng tôi có thể tránh để UUIDgiải trí với cài đặt lại và luôn luôn giống nhau UUIDcho cùng một ứng dụng ngay cả khi người dùng gỡ cài đặt và cài đặt lại.

UUID sẽ được tạo lại chỉ khi người dùng thiết lập lại thiết bị.

Tôi đã thử phương pháp này với SFHFKeychainUtils và nó hoạt động như một bùa mê.


33
Phương pháp này là một sự thay thế vững chắc cho UDID. Nó cũng có thêm lợi ích của việc tạo lại mã định danh theo định dạng thiết bị (ví dụ: nếu thiết bị thay đổi chủ sở hữu). Tuy nhiên, điều quan trọng cần lưu ý là móc khóa có thể được khôi phục sang các thiết bị khác nếu người dùng mã hóa bản sao lưu của họ. Điều này có thể dẫn đến tình huống nhiều thiết bị chia sẻ cùng một UUID. Để tránh điều này, hãy đặt khả năng truy cập của mục móc khóa của bạn thành kSecAttrAccessibleAlwaysThisDeviceOnly. Điều này sẽ đảm bảo rằng UUID của bạn không di chuyển sang bất kỳ thiết bị nào khác. Để truy cập UUID của bạn từ các ứng dụng khác, hãy sử dụng kSecAttrAccessGroupkhóa.
Jeevan Takhar

Trường hợp chính xác (khóa nào) bạn phải sử dụng để lưu trữ UUID trong móc khóa?
lostintranslation

Các bạn ạ! liên kết bị hỏng
COVID19

48

Tạo UUID của riêng bạn và sau đó lưu trữ trong Keychain. Do đó, nó vẫn tồn tại ngay cả khi ứng dụng của bạn được gỡ cài đặt. Trong nhiều trường hợp, nó cũng tồn tại ngay cả khi người dùng di chuyển giữa các thiết bị (ví dụ: sao lưu toàn bộ và khôi phục sang thiết bị khác).

Thực tế, nó trở thành một định danh người dùng duy nhất theo như bạn quan tâm. (thậm chí tốt hơn định danh thiết bị ).

Thí dụ:

Tôi đang xác định một phương thức tùy chỉnh để tạo UUIDnhư là:

- (NSString *)createNewUUID 
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

Sau đó, bạn có thể lưu trữ nó trong KEYCHAINlần ra mắt đầu tiên của ứng dụng. Vì vậy, sau lần ra mắt đầu tiên, chúng ta chỉ cần sử dụng nó từ móc khóa, không cần phải tạo lại nó. Lý do chính để sử dụng Keychain để lưu trữ là: Khi bạn đặt UUIDKeychain, nó sẽ tồn tại ngay cả khi người dùng gỡ cài đặt hoàn toàn Ứng dụng và sau đó cài đặt lại. . Vì vậy, đây là cách lưu trữ vĩnh viễn, có nghĩa là khóa sẽ là duy nhất theo mọi cách.

     #import "SSKeychain.h"
     #import <Security/Security.h>

Khi khởi động applictaion bao gồm mã sau:

 // getting the unique key (if present ) from keychain , assuming "your app identifier" as a key
       NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
      if (retrieveuuid == nil) { // if this is the first time app lunching , create key for device
        NSString *uuid  = [self createNewUUID];
// save newly created key to Keychain
        [SSKeychain setPassword:uuid forService:@"your app identifier" account:@"user"];
// this is the one time process
}

Tải xuống tệp SSKeychain.m và .h từ sskeychain và Kéo tệp SSKeychain.m và .h vào dự án của bạn và thêm "Security.framework" vào dự án của bạn. Để sử dụng UUID sau đó chỉ cần sử dụng:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];

Bởi vì một định danhForVendor đang hoạt động không hoàn hảo. Trong một số trường hợp có thể trả về nil hoặc 0x0. Phương pháp này có vẻ như đang hoạt động hoàn hảo
CReaTuS

3
Bất cứ ai đã xác thực điều này đang hoạt động trên iOS7 sau khi gỡ cài đặt / cài đặt lại chu kỳ + gửi ứng dụng apple đã xác minh?
mindbomb

Tôi đã bắt đầu sử dụng giải pháp này. Một số thử nghiệm trên 2 thiết bị (xây dựng lại, cài đặt lại, tắt thiết bị) cho tôi thấy rằng id là như nhau. iOS 10.3.
deko

16

Có lẽ bạn có thể sử dụng:

[UIDevice currentDevice].identifierForVendor.UUIDString

Tài liệu của Apple mô tả định danhForVender như sau:

Giá trị của thuộc tính này là giống nhau đối với các ứng dụng đến từ cùng một nhà cung cấp đang chạy trên cùng một thiết bị. Một giá trị khác được trả về cho các ứng dụng trên cùng một thiết bị đến từ các nhà cung cấp khác nhau và cho các ứng dụng trên các thiết bị khác nhau bất kể nhà cung cấp.


Tò mò tại sao không ai đưa ra điều này cho đến gần đây ... Và bây giờ tôi thấy nó mới với iOS 6.
James Boutcher

1
Nếu người dùng cập nhật ios và / hoặc cài đặt ios mới thì giá trị của định danhForVendor sẽ thay đổi hay giữ nguyên?
Sunil Zalavadiya

1
Sau khi xóa tất cả các ứng dụng khỏi cùng một nhà cung cấp thì giá trị này sẽ được thay đổi.
Mitesh Khatri

14

Bạn có thể muốn xem xét sử dụng OpenUDIDđó là một thay thế thả vào cho người không dùng nữa UDID.

Về cơ bản, để phù hợp với UDID, các tính năng sau được yêu cầu:

  1. độc đáo hoặc đủ độc đáo (va chạm xác suất thấp có lẽ rất dễ chấp nhận)
  2. kiên trì trên các lần khởi động lại, khôi phục, gỡ cài đặt
  3. có sẵn trên các ứng dụng của các nhà cung cấp khác nhau (hữu ích để có được người dùng thông qua mạng CPI) -

OpenUDID đáp ứng những điều trên và thậm chí có một cơ chế từ chối tích hợp để xem xét sau này.

Kiểm tra http://OpenUDID.org nó trỏ đến GitHub tương ứng. Hi vọng điêu nay co ich!

Là một lưu ý phụ, tôi sẽ né tránh bất kỳ thay thế địa chỉ MAC. Mặc dù địa chỉ MAC xuất hiện như một giải pháp hấp dẫn và phổ quát, hãy chắc chắn rằng loại quả treo thấp này bị nhiễm độc. Địa chỉ MAC rất nhạy cảm và Apple có thể không chấp nhận quyền truy cập vào địa chỉ này trước khi bạn có thể nói "ĐĂNG KÝ ỨNG DỤNG NÀY" ... địa chỉ mạng MAC được sử dụng để xác thực một số thiết bị trên các lans riêng (WLAN) hoặc riêng tư ảo khác mạng (VPN). .. nó thậm chí còn nhạy cảm hơn UDID trước đây!


Tôi thực sự tò mò làm thế nào điều này hoạt động? Mã được viết bằng Objective-C, nhưng không có giải pháp tốt nào khác phù hợp với các yêu cầu ở trên, vậy điều gì làm cho khung này khác biệt? Giải pháp mà khung này đang sử dụng cũng có thể được đăng dưới dạng câu trả lời được đề xuất tại đây ...
jake_hetfield

Tôi đồng tình - Địa chỉ MAC cũng có thể được cấu hình thủ công ("nhân bản"), mặc dù phần lớn nó không có khả năng. Tôi phải phản đối D trong UDID. Đây không phải là ID thiết bị, nó là UUID (Mã định danh duy nhất toàn cầu). ID thiết bị được Apple đóng dấu từ nhà máy trên mỗi thiết bị trong ROM.
Jay Imerman

Giải pháp tốt nhất cho iOS7 cũng như những gì thực sự cần thiết để xác định một thiết bị duy nhất
vishal dharankar

1
OpenUDID không được dùng nữa và không được khuyến nghị sử dụng
mkll 7/12/14

11

Tôi chắc chắn rằng Apple đã làm phiền nhiều người với sự thay đổi này. Tôi phát triển một ứng dụng kế toán cho iOS và có một dịch vụ trực tuyến để đồng bộ hóa các thay đổi được thực hiện trên các thiết bị khác nhau. Dịch vụ duy trì một cơ sở dữ liệu của tất cả các thiết bị và những thay đổi cần được truyền bá cho chúng. Do đó, điều quan trọng là phải biết thiết bị nào. Tôi đang theo dõi các thiết bị bằng cách sử dụng công cụ duy nhất của UIDevice và với những gì đáng giá, đây là suy nghĩ của tôi.

  • Tạo UUID và lưu trữ trong mặc định của người dùng? Không tốt vì điều này không tồn tại khi người dùng xóa ứng dụng. Nếu họ cài đặt lại sau đó, dịch vụ trực tuyến sẽ không tạo bản ghi thiết bị mới, điều đó sẽ gây lãng phí tài nguyên trên máy chủ và đưa ra danh sách các thiết bị chứa cùng một hoặc hai lần trở lên. Người dùng sẽ thấy nhiều hơn một "iPhone của Bob" được liệt kê nếu họ cài đặt lại ứng dụng.

  • Tạo UUID và lưu trữ trong móc khóa? Đây là kế hoạch của tôi, vì nó vẫn tồn tại ngay cả khi ứng dụng được gỡ cài đặt. Nhưng khi khôi phục bản sao lưu iTunes sang thiết bị iOS mới, móc khóa sẽ được chuyển nếu bản sao lưu được mã hóa. Điều này có thể dẫn đến hai thiết bị chứa cùng một id thiết bị nếu cả thiết bị cũ và mới đều đang hoạt động. Chúng nên được liệt kê dưới dạng hai thiết bị trong dịch vụ trực tuyến, ngay cả khi tên thiết bị giống nhau.

  • Tạo băm địa chỉ MAC và id gói? Đây có vẻ là giải pháp tốt nhất cho những gì tôi cần. Bằng cách băm với id gói, id thiết bị được tạo sẽ không cho phép thiết bị được theo dõi trên các ứng dụng và tôi nhận được một ID duy nhất cho kết hợp ứng dụng + thiết bị.

Thật thú vị khi lưu ý rằng tài liệu riêng của Apple đề cập đến việc xác thực các biên lai của Mac App Store bằng cách tính toán một hàm băm của địa chỉ MAC hệ thống cộng với id và phiên bản gói. Vì vậy, điều này dường như được cho phép bởi chính sách, cho dù nó có thông qua đánh giá ứng dụng mà tôi chưa biết.


10
Để tránh tình huống được mô tả trong điểm thứ hai của bạn, hãy đặt khả năng truy cập của mục móc khóa của bạn thành kSecAttrAccessibleAlwaysThisDeviceOnly. Điều này sẽ đảm bảo rằng UUID của bạn không khôi phục lại các thiết bị khác, ngay cả khi bản sao lưu được mã hóa.
Jeevan Takhar

Đây thực sự là hành vi tôi đã thấy nhiều lần. Ví dụ: tôi đăng ký iPhone của mình cho Google Sync. Sau đó, tôi đã nhận được một chiếc iPhone mới, đăng ký nó và voila - Bây giờ tôi có 2 chiếc iPhone được liệt kê trong cài đặt Đồng bộ hóa của mình.
Jay Imerman

11

Có vẻ như đối với iOS 6, Apple đang khuyên bạn nên sử dụng lớp NSUUID .

Từ thông báo bây giờ trong tài liệu UIDevice cho thuộc uniqueIdentifiertính:

Không dùng nữa trong iOS 5.0. Thay vào đó, hãy sử dụng thuộc tính định danhForVendor của lớp này hoặc thuộc tính AdvertisingIdentifier của lớp ASIdentifierManager, nếu phù hợp, hoặc sử dụng phương thức UUID của lớp NSUUID để tạo UUID và ghi nó vào cơ sở dữ liệu mặc định của người dùng.


10

Có thể trợ giúp: sử dụng mã bên dưới, nó sẽ luôn duy nhất trừ khi bạn xóa (Định dạng) thiết bị của mình.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];

1
Tôi đã sử dụng mã này. Nhưng khi tôi xóa ứng dụng và cài đặt lại, tôi đã nhận được Id mới
Durgaprasad

1
đây là một giải pháp đơn giản nếu bạn không cần một phương pháp mạnh mẽ. Tôi đang sử dụng nó trong ứng dụng của tôi bây giờ.
Reuben L.

@Durgaprasad: nó sẽ thay đổi luôn vì nó phụ thuộc vào nhà cung cấp. Ví dụ: 1. Nếu bạn đã cài đặt một ứng dụng với bundleidenedifier: com.abcd.com => thì nó sẽ thay đổi. 2. Nếu bạn đã cài đặt hai ứng dụng với bundleidenedifier: com.abcd.com => Sau đó, ứng dụng sẽ không hoạt động (Giữ bất kỳ một ứng dụng nào trong thời gian đó)
Ashvin Ajadiya

7

Tôi cũng xin đề nghị thay đổi theo từ uniqueIdentifierđến thư viện này mã nguồn mở (2 loại đơn giản thực sự) mà sử dụng các thiết bị địa chỉ MAC cùng với App Bundle nhận diện để tạo ra một ID duy nhất trong các ứng dụng của bạn mà có thể được sử dụng như một sự thay thế UDID.

Hãy nhớ rằng không giống như UDID, con số này sẽ khác nhau đối với mọi ứng dụng.

Bạn chỉ cần nhập bao gồm NSStringUIDevicecác danh mục và gọi [[UIDevice currentDevice] uniqueDeviceIdentifier]như vậy:

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"
NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]

Bạn có thể tìm thấy nó trên Github tại đây:

UIDevice với UniqueIdentifier cho iOS 5


Dưới đây là các danh mục (chỉ các tệp .m - kiểm tra dự án github cho các tiêu đề):

UIDevice + Định danhAddition.m

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"

#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

@interface UIDevice(Private)

- (NSString *) macaddress;

@end

@implementation UIDevice (IdentifierAddition)

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
- (NSString *) macaddress{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public Methods

- (NSString *) uniqueDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
    NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
    NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
    return uniqueIdentifier;
}

- (NSString *) uniqueGlobalDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *uniqueIdentifier = [macaddress stringFromMD5];    
    return uniqueIdentifier;
}

@end

NSString + MD5Addition.m:

#import "NSString+MD5Addition.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString(MD5Addition)

- (NSString *) stringFromMD5{
    
    if(self == nil || [self length] == 0)
        return nil;
    
    const char *value = [self UTF8String];
    
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);
    
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    return [outputString autorelease];
}

@end

3
Bắt đầu từ iOS 7, Apple sẽ trả về giá trị không đổi cho địa chỉ MAC. Nó làm cho ý nghĩa hoàn hảo. Địa chỉ MAC rất nhạy cảm.
Roberto


4

Địa chỉ MAC có thể bị giả mạo khiến cho cách tiếp cận như vậy trở nên vô dụng khi buộc nội dung cho người dùng cụ thể hoặc thực hiện các tính năng bảo mật như danh sách đen.

Sau một số nghiên cứu sâu hơn, có vẻ như chúng ta đã rời đi mà không có sự thay thế thích hợp như bây giờ. Tôi thực sự hy vọng Apple sẽ xem xét lại quyết định của họ.

Có lẽ sẽ là một ý tưởng tốt để gửi email cho Apple về chủ đề này và / hoặc gửi yêu cầu lỗi / tính năng về vấn đề này vì có thể họ thậm chí không nhận thức được hậu quả đầy đủ cho các nhà phát triển.


13
Tuy nhiên, một điểm hợp lệ tôi tin rằng UUID cũng có thể bị giả mạo / làm mờ trên điện thoại đã bẻ khóa, vì vậy về mặt kỹ thuật, [UIDevice uniqueIdentifier] hiện tại là hoàn hảo.
Oliver Pearmain

3
Bạn luôn có thể tạo một định danh trên máy chủ và lưu nó trên thiết bị. Đó là cách hầu hết các ứng dụng làm điều đó. Tôi không hiểu tại sao lập trình viên iOS cần thứ gì đó đặc biệt.
Sulthan

1
@Sulthan không hoạt động trên iOS vì nếu bạn gỡ cài đặt một ứng dụng thì tất cả dữ liệu của nó sẽ biến mất, vì vậy không có cách nào để đảm bảo một định danh thiết bị duy nhất theo cách đó.
lkraider

4
Không, nếu bạn lưu nó vào móc khóa. Dù sao, tôi chưa bao giờ thấy một ứng dụng mà đây là một vấn đề. Nếu ứng dụng và dữ liệu đã bị xóa, bạn không cần cùng một mã định danh thiết bị. Nếu bạn muốn xác định người dùng, hãy hỏi anh ta email.
Sulthan

Truy cập địa chỉ MAC cũng đã bị Apple cấm trong bản phát hành mới của iOS;
Ans

4

UIDevice identifierForVendor được giới thiệu trong iOS 6 sẽ hoạt động cho mục đích của bạn.

identifierForVendorlà một chuỗi ký tự chữ và số xác định duy nhất một thiết bị cho nhà cung cấp ứng dụng. (chỉ đọc)

@property(nonatomic, readonly, retain) NSUUID *identifierForVendor

Giá trị của thuộc tính này là giống nhau đối với các ứng dụng đến từ cùng một nhà cung cấp đang chạy trên cùng một thiết bị. Một giá trị khác nhau được trả về cho các ứng dụng cùng một thiết bị đến từ các nhà cung cấp khác nhau và cho các ứng dụng trên các thiết bị khác nhau liên quan đến nhà cung cấp.

Có sẵn trong iOS 6.0 trở lên và được khai báo trong UIDevice.h

Đối với iOS 5, hãy tham khảo liên kết này UIDevice-with-UniqueIdentifier-for-iOS-5


4

Sử dụng SSKeychain và mã được đề cập ở trên. Đây là mã để sao chép / dán (thêm mô-đun SSKeychain):

+(NSString *) getUUID {

//Use the bundle name as the App identifier. No need to get the localized version.

NSString *Appname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];    

//Check if we have UUID already

NSString *retrieveuuid = [SSKeychain passwordForService:Appname account:@"user"];

if (retrieveuuid == NULL)
{

    //Create new key for this app/device

    CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);

    retrieveuuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);

    CFRelease(newUniqueId);

    //Save key to Keychain
    [SSKeychain setPassword:retrieveuuid forService:Appname account:@"user"];
}

return retrieveuuid;

}


3

Mã sau giúp lấy UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);

3

Đây là mã tôi đang sử dụng để nhận ID cho cả iOS 5 và iOS 6, 7:

- (NSString *) advertisingIdentifier
{
    if (!NSClassFromString(@"ASIdentifierManager")) {
        SEL selector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:selector]) {
            return [[UIDevice currentDevice] performSelector:selector];
        }
    }
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

Bạn làm gì về cảnh báo trình biên dịch PerformSelector may cause a leak because its selector is unknown?
Basil Bourque

Bạn không thể sử dụng AdvertisingIdentifier nữa cho mục đích này vì Apple sẽ từ chối nó. Thông tin thêm: techcrunch.com/2014/02/03/ Từ
codeplasma


2

iOS 11 đã giới thiệu khung DeviceCheck. Nó có một giải pháp đầy đủ để xác định duy nhất thiết bị.


1

Một cách làm việc để có được UDID:

  1. Khởi chạy một máy chủ web bên trong ứng dụng có hai trang: một trang sẽ trả về cấu hình MobileConfiguration được chế tạo đặc biệt và một trang khác sẽ thu thập UDID. Thêm thông tin ở đây , đâyđây .
  2. Bạn mở trang đầu tiên trong Mobile Safari từ bên trong ứng dụng và nó chuyển hướng bạn đến Settings.app yêu cầu cài đặt cấu hình cấu hình. Sau khi bạn cài đặt hồ sơ, UDID được gửi đến trang web thứ hai và bạn có thể truy cập nó từ bên trong ứng dụng. (Settings.app có tất cả các quyền lợi cần thiết và các quy tắc hộp cát khác nhau).

Một ví dụ sử dụng RoutingHTTPServer :

import UIKit
import RoutingHTTPServer

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var bgTask = UIBackgroundTaskInvalid
    let server = HTTPServer()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        application.openURL(NSURL(string: "http://localhost:55555")!)
        return true
    }

    func applicationDidEnterBackground(application: UIApplication) {
        bgTask = application.beginBackgroundTaskWithExpirationHandler() {
            dispatch_async(dispatch_get_main_queue()) {[unowned self] in
                application.endBackgroundTask(self.bgTask)
                self.bgTask = UIBackgroundTaskInvalid
            }
        }
    }
}

class HTTPServer: RoutingHTTPServer {
    override init() {
        super.init()
        setPort(55555)
        handleMethod("GET", withPath: "/") {
            $1.setHeader("Content-Type", value: "application/x-apple-aspen-config")
            $1.respondWithData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("udid", ofType: "mobileconfig")!)!)
        }
        handleMethod("POST", withPath: "/") {
            let raw = NSString(data:$0.body(), encoding:NSISOLatin1StringEncoding) as! String
            let plistString = raw.substringWithRange(Range(start: raw.rangeOfString("<?xml")!.startIndex,end: raw.rangeOfString("</plist>")!.endIndex))
            let plist = NSPropertyListSerialization.propertyListWithData(plistString.dataUsingEncoding(NSISOLatin1StringEncoding)!, options: .allZeros, format: nil, error: nil) as! [String:String]

            let udid = plist["UDID"]! 
            println(udid) // Here is your UDID!

            $1.statusCode = 200
            $1.respondWithString("see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html")
        }
        start(nil)
    }
}

Dưới đây là nội dung của udid.mobileconfig:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>PayloadContent</key>
        <dict>
            <key>URL</key>
            <string>http://localhost:55555</string>
            <key>DeviceAttributes</key>
            <array>
                <string>IMEI</string>
                <string>UDID</string>
                <string>PRODUCT</string>
                <string>VERSION</string>
                <string>SERIAL</string>
            </array>
        </dict>
        <key>PayloadOrganization</key>
        <string>udid</string>
        <key>PayloadDisplayName</key>
        <string>Get Your UDID</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadUUID</key>
        <string>9CF421B3-9853-9999-BC8A-982CBD3C907C</string>
        <key>PayloadIdentifier</key>
        <string>udid</string>
        <key>PayloadDescription</key>
        <string>Install this temporary profile to find and display your current device's UDID. It is automatically removed from device right after you get your UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

Việc cài đặt hồ sơ sẽ thất bại (tôi không bận tâm thực hiện phản hồi dự kiến, xem tài liệu ), nhưng ứng dụng sẽ nhận được UDID chính xác. Và bạn cũng nên ký tên Mobileconfig .


1

Đối với Swift 3.0, vui lòng sử dụng mã bên dưới.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)

1
iOS 11 đã giới thiệu khung DeviceCheck. Nó có một giải pháp đầy đủ để xác định duy nhất thiết bị.
Santosh Botre

1

Bạn có thể dùng

NSString *sID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

Đó là duy nhất cho các thiết bị trong tất cả các ứng dụng.



0

Nếu ai đó vấp phải câu hỏi này, khi tìm kiếm một giải pháp thay thế. Tôi đã theo phương pháp này trong IDManagerlớp, Đây là một bộ sưu tập từ các giải pháp khác nhau. KeyChainUtil là một trình bao bọc để đọc từ móc khóa. Bạn cũng có thể sử dụng hashed MAC addressnhư một loại ID duy nhất.

/*  Apple confirmed this bug in their system in response to a Technical Support Incident 
    request. They said that identifierForVendor and advertisingIdentifier sometimes 
    returning all zeros can be seen both in development builds and apps downloaded over the 
    air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID             @"00000000-0000-0000-0000-000000000000"

+ (NSString *) getUniqueID {
    if (NSClassFromString(@"ASIdentifierManager")) {
        NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
        if ([asiID compare:kBuggyASIID] == NSOrderedSame) {
            NSLog(@"Error: This device return buggy advertisingIdentifier.");
            return [IDManager getUniqueUUID];
        } else {
            return asiID;
        }

    } else {
        return [IDManager getUniqueUUID];
    }
}


+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

/* NSUUID is after iOS 6. */
+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address
// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress
{
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;

    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;

    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }

    if ((buf = malloc(len)) == NULL) {
        printf("Error: Memory allocation error\n");
        return NULL;
    }

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        return NULL;
    }

    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

    free(buf);
    return outstring;
}

+ (NSString *) getHashedMACAddress
{
    NSString * mac = [IDManager getMACAddress];
    return [Util md5String:mac];
}

+ (NSString *)md5String:(NSString *)plainText
{
    if(plainText == nil || [plainText length] == 0)
        return nil;

    const char *value = [plainText UTF8String];
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);

    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    NSString * retString = [NSString stringWithString:outputString];
    [outputString release];
    return retString;
}

0
+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
    NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
    return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

0

Chúng tôi có thể sử dụng định danhForVendor cho ios7,

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

--Lưu ý quan trọng ---

UDID và định danhForVendor khác nhau: ---

1.) On uninstalling  and reinstalling the app identifierForVendor will change.

2.) The value of identifierForVendor remains the same for all the apps installed from the same vendor on the device.

3.) The value of identifierForVendor also changes for all the apps if any of the app (from same vendor) is reinstalled.

bạn có chắc không ? chúng ta có thể sử dụng định danhForVendor cho ios7 không?
Avis

0

Apple đã ẩn UDID khỏi tất cả các API công khai, bắt đầu với iOS 7. Bất kỳ UDID nào bắt đầu bằng FFFF đều là ID giả. Các ứng dụng "Gửi UDID" trước đây không còn được sử dụng để thu thập UDID cho các thiết bị thử nghiệm. (thở dài!)

UDID được hiển thị khi thiết bị được kết nối với XCode (trong trình tổ chức) và khi thiết bị được kết nối với iTunes (mặc dù bạn phải nhấp vào 'Số sê-ri' để hiển thị Số nhận dạng.

Nếu bạn cần lấy UDID cho thiết bị để thêm vào hồ sơ cung cấp và không thể tự làm điều đó trong XCode, bạn sẽ phải hướng dẫn chúng qua các bước để sao chép / dán nó từ iTunes.

Có cách nào kể từ khi (phát hành iOS 7) để có được UDID mà không cần sử dụng iTunes trên PC / Mac không?


0

Tôi cũng có một số vấn đề và giải pháp rất đơn giản:

    // Get Bundle Info for Remote Registration (handy if you have more than one app)
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];


    // Get the users Device Model, Display Name, Unique ID, Token & Version Number
    UIDevice *dev = [UIDevice currentDevice];
    NSString *deviceUuid=[dev.identifierForVendor  UUIDString];

    NSString *deviceName = dev.name;

0

Một sự thay thế không hoàn hảo nhưng là một trong những giải pháp thay thế tốt nhất và gần nhất với UDID (trong Swift sử dụng iOS 8.1 và Xcode 6.1):

Tạo UUID ngẫu nhiên

let strUUID: String = NSUUID().UUIDString

Và sử dụng thư viện KeychainWrapper :

Thêm một giá trị chuỗi vào móc khóa:

let saveSuccessful: Bool = KeychainWrapper.setString("Some String", forKey: "myKey")

Lấy một giá trị chuỗi từ móc khóa:

let retrievedString: String? = KeychainWrapper.stringForKey("myKey")

Xóa giá trị chuỗi khỏi móc khóa:

let removeSuccessful: Bool = KeychainWrapper.removeObjectForKey("myKey")

Giải pháp này sử dụng móc khóa, do đó bản ghi được lưu trong móc khóa sẽ được duy trì, ngay cả sau khi ứng dụng được gỡ cài đặt và cài đặt lại. Cách duy nhất để xóa bản ghi này là Đặt lại tất cả nội dung và cài đặt của thiết bị. Đó là lý do tại sao tôi đã đề cập rằng giải pháp thay thế này không hoàn hảo nhưng vẫn là một trong những giải pháp thay thế tốt nhất cho UDID trên iOS 8.1 bằng Swift.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.