UIDevice uniqueIdentifier sudah usang - Apa yang harus dilakukan sekarang?

501

Baru saja terungkap bahwa properti UIDevice uniqueIdentifier sudah ditinggalkan di iOS 5 dan tidak tersedia di iOS 7 dan di atasnya. Tidak ada metode atau properti alternatif yang tampaknya tersedia atau akan datang.

Banyak aplikasi kami yang ada sangat tergantung pada properti ini untuk mengidentifikasi perangkat tertentu secara unik. Bagaimana kita menangani masalah ini ke depan?

Saran dari dokumentasi pada 2011-2012 adalah:

Pertimbangan Khusus

Jangan gunakan properti uniqueIdentifier. Untuk membuat pengidentifikasi unik khusus untuk aplikasi Anda, Anda dapat memanggil CFUUIDCreatefungsi untuk membuat UUID, dan menulisnya ke database default menggunakan NSUserDefaultskelas.

Namun nilai ini tidak akan sama jika pengguna mencopot pemasangan dan menginstal ulang aplikasi.

Oliver Pearmain
sumber
1
Untuk aplikasi yang masih menggunakan uniqueIdentifier, iOS7 sekarang mengembalikan FFFFFFFF + identifierForVendor yang melanggar banyak aplikasi berlangganan yang tidak diperpanjang yang ditulis dengan buruk.
Fistman Berirama
Jika kebetulan aplikasi Anda menggunakan Push Notifications, Anda dapat menggunakan token yang dikirim kembali dari layanan push apple, itu unik per perangkat juga
Calin Chitu
@CalinChitu Jika pengguna tidak menerima pemberitahuan push, apakah Anda masih mendapatkan pushID untuk pengguna itu?
Chase Roberts

Jawaban:

272

Sebuah UUID yang dibuat oleh CFUUIDCreate adalah unik jika pencopotan pemasangan pengguna dan re-menginstal aplikasi: Anda akan mendapatkan yang baru setiap kali.

Tetapi Anda mungkin ingin itu tidak unik, yaitu harus tetap sama ketika pengguna mencopot pemasangan dan menginstal ulang aplikasi. Ini membutuhkan sedikit usaha, karena pengidentifikasi per-perangkat yang paling dapat diandalkan tampaknya adalah alamat MAC. Anda dapat meminta MAC dan menggunakannya sebagai UUID.

Sunting: Orang perlu selalu menanyakan MAC dari antarmuka yang sama, tentu saja. Saya kira taruhan terbaik adalah dengan en0. MAC selalu ada, bahkan jika antarmuka tidak memiliki IP / turun.

Sunting 2: Seperti yang ditunjukkan oleh orang lain, solusi yang lebih disukai karena iOS 6 adalah - [UIDevice identifierForVendor] . Dalam kebanyakan kasus, Anda harus dapat menggunakannya sebagai pengganti drop-in ke yang lama -[UIDevice uniqueIdentifier](tetapi UUID yang dibuat ketika aplikasi dimulai untuk pertama kalinya adalah apa yang Apple ingin Anda gunakan).

Sunting 3: Jadi poin utama ini tidak hilang dalam kebisingan komentar: jangan gunakan MAC sebagai UUID, buat hash menggunakan MAC . Hash itu akan selalu menciptakan hasil yang sama setiap kali, bahkan di seluruh menginstal ulang dan aplikasi (jika hashing dilakukan dengan cara yang sama). Bagaimanapun, saat ini (2013) ini tidak diperlukan lagi kecuali jika Anda memerlukan pengenal perangkat "stabil" di iOS <6.0.

Sunting 4: Di iOS 7, Apple sekarang selalu mengembalikan nilai tetap ketika meminta MAC untuk secara spesifik menggagalkan MAC sebagai basis untuk skema ID . Jadi Anda sekarang benar-benar harus menggunakan - [UIDevice identifierForVendor] atau membuat UUID per-instal.

DarkDust
sumber
8
Apakah alamat mac tidak berubah tergantung pada apakah pengguna terhubung melalui Wifi atau tidak?
Oliver Pearmain
1
@DarkDust: tetapi karena antarmuka yang aktif berubah ketika Anda beralih dari wifi ke modem seluler, alamat MAC dari antarmuka yang aktif juga harus berubah; kecuali Anda selalu memilih antarmuka tertentu untuk mendapatkan MAC
user102008
3
@Roger Nolan: Tolong jangan edit jawaban orang lain dan tambahkan hal-hal yang sepertinya berasal dari penulis asli. Terima kasih.
DarkDust
2
@RogerNolan Selama posting bukan jawaban komunitas, hasil edit adalah untuk memperbaiki kesalahan dan hal-hal semacam itu, bukan untuk menambahkan hal baru. Ada alasan Anda mendapatkan hak istimewa. Bayangkan saya mengedit jawaban Anda dan menulis beberapa BS, orang akan berpikir Anda akan menulis itu. Saya ragu Anda akan menyukainya :-) Tetapi Anda tidak mendapatkan pemberitahuan bahwa pengeditan terjadi, saya hanya mengetahui secara tidak sengaja.
DarkDust
3
Apple sekarang menolak aplikasi yang menggunakan MAC hash.
Idan
91

Anda sudah bisa menggunakan alternatif Anda untuk Apple UDID. Kind guy gekitz menulis kategori UIDeviceyang akan menghasilkan beberapa jenis UDIDberdasarkan pada perangkat mac-address dan bundle identifier.

Anda dapat menemukan kode di github

Serhii Mamontov
sumber
3
Implementasi ini adalah unik (alamat MAC) untuk perangkat di seluruh instalasi ulang, seperti Apple uniqueId, tetapi juga menghormati privasi, juga unik untuk aplikasi (juga menggunakan bundleId) ... A harus memiliki imho, yang harus dimasukkan Apple dalam API-nya. .. bukannya mencela tanpa alternatif apa pun.
Vincent Guerci
8
Meskipun menggunakan lisensi bsd gaya lama dengan klausa iklan, huek.
jbtule
8
Untuk orang lain yang sekarang menemukan posting ini, lisensi telah diubah sejak komentar di atas oleh jbtule.
James
1
Sebagaimana dibahas dalam komentar komit ini, perpustakaan apa adanya menimbulkan masalah kebocoran privasi yang serius dan tidak boleh digunakan:
Akan
15
Mulai dari iOS 7, sistem selalu mengembalikan nilai 02:00:00:00:00:00ketika Anda meminta alamat MAC pada perangkat apa pun. Periksa di sini: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi
61

Berdasarkan tautan yang diusulkan oleh @moonlight, saya melakukan beberapa tes dan sepertinya itu solusi terbaik. Seperti @DarkDust mengatakan metode ini untuk memeriksa en0yang selalu tersedia.
Ada 2 opsi:
uniqueDeviceIdentifier(MD5 dari MAC + CFBundleIdentifier)
dan uniqueGlobalDeviceIdentifier(MD5 dari MAC), ini selalu mengembalikan nilai yang sama.
Di bawah tes yang telah saya lakukan (dengan perangkat asli):

#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 - (mode AirPlane) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (mode AirPlane) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) setelah menghapus dan menginstal ulang aplikasi XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) setelah menghapus dan menginstal aplikasi

Semoga bermanfaat.

EDIT:
Seperti yang ditunjukkan orang lain, solusi ini di iOS 7 tidak lagi berguna karena uniqueIdentifiertidak lagi tersedia dan permintaan untuk alamat MAC sekarang kembali selalu 02: 00: 00: 00: 00: 00: 00

Tikar
sumber
13
ini tidak akan berfungsi pada iOS7, Apple menghilangkan penggunaan alamat MAC.
Sarim Sidd
@SarimSidd Untuk saat ini informasi tentang iOS 7 berada di bawah NDA, kami tidak dapat membahasnya di sini.
Mat
57

lihat ini,

kita bisa menggunakan Keychain alih-alih NSUserDefaultskelas, untuk menyimpan yang UUIDdibuat oleh CFUUIDCreate.

dengan cara ini kita dapat menghindari untuk UUIDrekreasi dengan menginstal ulang, dan mendapatkan selalu sama UUIDuntuk aplikasi yang sama bahkan pengguna menghapus dan menginstal ulang lagi.

UUID akan dibuat ulang tepat saat perangkat disetel ulang oleh pengguna.

Saya mencoba metode ini dengan SFHFKeychainUtils dan ini berfungsi seperti pesona.

ytur
sumber
33
Metode ini merupakan pengganti yang solid untuk UDID. Ini juga memiliki manfaat tambahan untuk membuat ulang pengenal pada format perangkat (mis. Jika perangkat berubah pemilik). Namun, penting untuk dicatat bahwa gantungan kunci dapat dipulihkan ke perangkat lain jika pengguna mengenkripsi cadangan mereka. Ini dapat mengakibatkan situasi di mana beberapa perangkat berbagi UUID yang sama. Untuk menghindari ini, atur aksesibilitas item gantungan kunci Anda ke kSecAttrAccessibleAlwaysThisDeviceOnly. Ini akan memastikan bahwa UUID Anda tidak bermigrasi ke perangkat lain. Untuk mengakses UUID Anda dari aplikasi lain, gunakan kSecAttrAccessGroupkuncinya.
Jeevan Takhar
Di mana tepatnya (kunci mana) yang seharusnya Anda gunakan untuk menyimpan UUID di gantungan kunci?
lostintranslation
Opps! tautan rusak
COVID19
48

Buat UUID Anda sendiri dan kemudian simpan di Keychain. Dengan demikian itu tetap ada bahkan ketika aplikasi Anda dihapus instalasinya. Dalam banyak kasus itu juga tetap ada bahkan jika pengguna bermigrasi di antara perangkat (mis. Cadangan penuh dan mengembalikan ke perangkat lain).

Secara efektif itu menjadi pengidentifikasi pengguna unik sejauh yang Anda khawatirkan. (bahkan lebih baik daripada pengenal perangkat ).

Contoh:

Saya mendefinisikan metode khusus untuk membuat UUIDsebagai:

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

Anda kemudian dapat menyimpannya KEYCHAINpada saat peluncuran aplikasi Anda yang pertama. Sehingga setelah peluncuran pertama, kita cukup menggunakannya dari gantungan kunci, tidak perlu dibuat ulang. Alasan utama untuk menggunakan Keychain untuk menyimpan adalah: Ketika Anda mengatur UUIDke Keychain, itu akan tetap ada bahkan jika pengguna benar-benar menghapus instalan Aplikasi dan kemudian menginstalnya lagi. . Jadi, ini adalah cara permanen menyimpannya, yang berarti kuncinya akan unik sepanjang jalan.

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

Pada peluncuran aplikasi termasuk kode berikut:

 // 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
}

Unduh file SSKeychain.m dan .h dari sskeychain dan Tarik file SSKeychain.m dan .h ke proyek Anda dan tambahkan "Security.framework" ke proyek Anda. Untuk menggunakan UUID sesudahnya cukup gunakan:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Samir Jwarchan
sumber
Karena identifierForVendor berfungsi tidak sempurna. Dalam beberapa kasus dapat mengembalikan nol atau 0x0. Metode ini tampaknya bekerja dengan sempurna
CReaTuS
3
Adakah yang memvalidasi ini bekerja di iOS7 setelah uninstall / instal ulang siklus + pengajuan aplikasi apple diverifikasi?
mindbomb
Saya sudah mulai menggunakan solusi ini. Beberapa tes pada 2 perangkat (membangun kembali, menginstal ulang, mematikan perangkat) menunjukkan kepada saya bahwa id adalah sama. iOS 10.3.
deko
16

Mungkin Anda bisa menggunakan:

[UIDevice currentDevice].identifierForVendor.UUIDString

Dokumentasi Apple menjelaskan identifierForVender sebagai berikut:

Nilai properti ini sama untuk aplikasi yang berasal dari vendor yang sama yang berjalan di perangkat yang sama. Nilai yang berbeda dikembalikan untuk aplikasi pada perangkat yang sama yang berasal dari vendor yang berbeda, dan untuk aplikasi pada perangkat yang berbeda terlepas dari vendor.

Diadyne
sumber
Penasaran mengapa tidak ada yang membawa ini sampai saat ini ... Dan sekarang saya melihat ini baru dengan iOS 6.
James Boutcher
1
Jika pengguna memperbarui ios dan / atau menginstal ios baru maka nilai identifierForVendor akan berubah atau tetap sama?
Sunil Zalavadiya
1
Setelah menghapus semua aplikasi dari vendor yang sama maka nilai ini akan berubah.
Mitesh Khatri
14

Anda mungkin ingin mempertimbangkan untuk menggunakan OpenUDIDpengganti drop-in untuk yang sudah usang UDID.

Pada dasarnya, untuk mencocokkan UDID, fitur berikut diperlukan:

  1. unik atau cukup unik (tabrakan probabilitas rendah mungkin sangat dapat diterima)
  2. kegigihan di seluruh reboot, mengembalikan, meng-uninstall sepenuhnya
  3. tersedia di seluruh aplikasi vendor yang berbeda (berguna untuk memperoleh pengguna melalui jaringan CPI) -

OpenUDID memenuhi hal di atas dan bahkan memiliki mekanisme Opt-Out built-in untuk pertimbangan nanti.

Periksa http://OpenUDID.org itu menunjuk ke GitHub yang sesuai. Semoga ini membantu!

Sebagai catatan, saya akan menghindar dari alternatif alamat MAC. Meskipun alamat MAC tampak seperti solusi yang menggoda dan universal, pastikan buah yang menggantung rendah ini diracuni. Alamat MAC sangat sensitif, dan Apple mungkin akan mencabut akses ke yang ini sebelum Anda bahkan dapat mengatakan "SUBMIT THIS APP" ... alamat jaringan MAC digunakan untuk mengautentikasi perangkat tertentu pada lans pribadi (WLAN) atau virtual private lainnya. jaringan (VPN). .. ini bahkan lebih sensitif daripada mantan UDID!

ylechelle
sumber
Saya benar-benar ingin tahu bagaimana ini bekerja? Kode ini ditulis dalam Objective-C, tetapi tidak ada solusi bagus lainnya yang sesuai dengan persyaratan di atas, jadi apa yang membuat kerangka kerja ini berbeda? Solusi yang digunakan kerangka kerja ini juga harus memungkinkan untuk dikirim sebagai jawaban yang disarankan di sini ...
jake_hetfield
Saya setuju - alamat MAC juga dapat dikonfigurasikan secara manual ("dikloning"), meskipun tidak mungkin untuk sebagian besar. Saya harus memprotes D di UDID. Ini bukan Device ID, ini adalah UUID (Pengidentifikasi Unik Universal). ID Perangkat dicap oleh Apple dari pabrik di setiap perangkat dalam ROM.
Jay Imerman
Solusi terbaik untuk iOS7 juga melakukan apa yang sebenarnya dibutuhkan untuk mengidentifikasi perangkat secara unik
vishal dharankar
1
OpenUDID sudah usang dan tidak direkomendasikan untuk digunakan
mkll
11

Saya yakin Apple telah mengganggu banyak orang dengan perubahan ini. Saya mengembangkan aplikasi pembukuan untuk iOS dan memiliki layanan online untuk menyinkronkan perubahan yang dibuat pada perangkat yang berbeda. Layanan memelihara database semua perangkat dan perubahan yang perlu disebarkan ke mereka. Karena itu penting untuk mengetahui perangkat mana yang mana. Saya melacak perangkat menggunakan UIDevice uniqueIdentifier dan untuk apa nilainya, inilah pemikiran saya.

  • Buat UUID dan simpan di default pengguna? Tidak bagus karena ini tidak berlanjut ketika pengguna menghapus aplikasi. Jika mereka menginstal lagi nanti layanan online seharusnya tidak membuat catatan perangkat baru, yang akan membuang sumber daya di server dan memberikan daftar perangkat yang berisi yang sama dua atau lebih kali. Pengguna akan melihat lebih dari satu "iPhone Bob" terdaftar jika mereka menginstal ulang aplikasi.

  • Buat UUID dan simpan di gantungan kunci? Ini adalah rencana saya, karena tetap ada bahkan ketika aplikasi dihapus. Tetapi ketika mengembalikan cadangan iTunes ke perangkat iOS baru, gantungan kunci ditransfer jika cadangan dienkripsi. Ini dapat menyebabkan dua perangkat yang berisi id perangkat yang sama jika perangkat lama dan baru keduanya dalam layanan. Ini harus terdaftar sebagai dua perangkat dalam layanan online, bahkan jika nama perangkat itu sama.

  • Hasilkan hash alamat MAC dan id bundel? Ini sepertinya solusi terbaik untuk apa yang saya butuhkan. Dengan hashing dengan bundle id, id perangkat yang dihasilkan tidak akan memungkinkan perangkat untuk dilacak di seluruh aplikasi dan saya mendapatkan ID unik untuk kombinasi aplikasi + perangkat.

Sangat menarik untuk dicatat bahwa dokumentasi Apple sendiri mengacu pada memvalidasi penerimaan Mac App Store dengan menghitung hash dari sistem alamat MAC ditambah id bundel dan versi. Jadi ini sepertinya diizinkan oleh kebijakan, apakah itu melewati ulasan aplikasi saya belum tahu.

Mathew Waters
sumber
10
Untuk menghindari situasi yang dijelaskan pada poin kedua Anda, atur aksesibilitas item gantungan kunci Anda ke kSecAttrAccessibleAlwaysThisDeviceOnly. Ini akan memastikan bahwa UUID Anda tidak dikembalikan ke perangkat lain, bahkan jika cadangannya dienkripsi.
Jeevan Takhar
Ini memang perilaku yang telah saya lihat berkali-kali. Sebagai contoh, saya mendaftarkan iPhone saya ke Google Sync. Lalu saya mendapatkan iPhone baru, mendaftar, dan voila - Saya sekarang memiliki 2 iPhone yang terdaftar di pengaturan Sync saya.
Jay Imerman
11

Sepertinya untuk iOS 6, Apple merekomendasikan Anda menggunakan kelas NSUUID .

Dari pesan sekarang di dokumen UIDevice untuk uniqueIdentifierproperti:

Sudah usang di iOS 5.0. Gunakan properti identifierForVendor dari kelas ini atau properti advertisingIdentifier dari kelas ASIdentifierManager, yang sesuai, atau gunakan metode UUID dari kelas NSUUID untuk membuat UUID dan menulisnya ke database default pengguna.

Nate
sumber
10

Boleh bantu: gunakan kode di bawah ini akan selalu Unik kecuali Anda menghapus (Memformat) perangkat Anda.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Ashvin Ajadiya
sumber
1
Saya menggunakan kode ini. Tetapi ketika saya menghapus aplikasi dan menginstal lagi saya mendapat Id baru
Durgaprasad
1
ini adalah solusi sederhana jika Anda tidak memerlukan metode yang kuat. Saya menggunakannya di aplikasi saya sekarang.
Reuben L.
@Durgaprasad: itu akan berubah selalu karena tergantung pada vendor. Misalnya: 1. Jika Anda telah menginstal aplikasi dengan bundleidenedifier: com.abcd.com => maka itu akan berubah. 2. Jika Anda telah menginstal dua aplikasi dengan bundleidenedifier: com.abcd.com => Maka itu tidak akan berkurang (Simpan satu aplikasi selama)
Ashvin Ajadiya
7

Saya juga akan menyarankan berubah dari dari uniqueIdentifierke perpustakaan open source ini (2 kategori sederhana benar-benar) yang memanfaatkan perangkat MAC Address bersama dengan App Bundle Identifier untuk menghasilkan ID unik dalam aplikasi Anda yang dapat digunakan sebagai pengganti UDID.

Ingatlah bahwa tidak seperti UDID, angka ini akan berbeda untuk setiap aplikasi.

Anda hanya perlu mengimpor yang termasuk NSStringdan UIDevicekategori dan menyebutnya [[UIDevice currentDevice] uniqueDeviceIdentifier]seperti:

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

Anda dapat menemukannya di Github di sini:

UIDevice dengan UniqueIdentifier untuk iOS 5


Berikut adalah kategorinya (hanya file .m - periksa proyek github untuk melihat headernya):

UIDevice + IdentifierAddition.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
dikunyah
sumber
3
Mulai di iOS 7, Apple akan mengembalikan nilai konstan untuk alamat MAC. Masuk akal. Alamat MAC sensitif.
Roberto
4

Alamat MAC dapat dipalsukan yang membuat pendekatan seperti itu tidak berguna untuk mengikat konten ke pengguna tertentu atau mengimplementasikan fitur keamanan seperti daftar hitam.

Setelah beberapa penelitian lebih lanjut tampak bagi saya bahwa kita tidak memiliki alternatif yang tepat seperti sekarang Saya sungguh berharap Apple akan mempertimbangkan kembali keputusan mereka.

Mungkin itu ide yang baik untuk mengirim email ke Apple tentang topik ini dan / atau mengajukan permintaan bug / fitur tentang ini karena mungkin mereka bahkan tidak menyadari konsekuensi penuh untuk pengembang.

Toastor
sumber
13
Namun poin yang valid saya percaya bahwa UUID juga dapat dipalsukan / di-swizzle pada ponsel yang sudah di-jailbreak sehingga secara teknis [UIDevice uniqueIdentifier] yang ada sama cacatnya.
Oliver Pearmain
3
Anda selalu dapat membuat pengenal di server dan menyimpannya di perangkat. Begitulah cara sebagian besar aplikasi melakukannya. Saya tidak mengerti mengapa programmer iOS membutuhkan sesuatu yang istimewa.
Sulthan
1
@Sulthan tidak berfungsi di iOS karena jika Anda menghapus aplikasi, semua datanya hilang, jadi tidak ada cara untuk menjamin pengidentifikasi perangkat unik dengan cara itu.
lkraider
4
Tidak jika Anda menyimpannya di gantungan kunci. Lagi pula, saya belum pernah melihat aplikasi di mana ini menjadi masalah. Jika aplikasi dan data telah dihapus, Anda tidak perlu pengenal perangkat yang sama. Jika Anda ingin mengidentifikasi pengguna, minta dia untuk email.
Sulthan
Akses alamat MAC juga telah dilarang oleh Apple dalam rilis baru iOS;
Ans
4

UIDevice identifierForVendor diperkenalkan di iOS 6 akan berfungsi untuk tujuan Anda.

identifierForVendoradalah string alfanumerik yang secara unik mengidentifikasi perangkat ke vendor aplikasi. (hanya baca)

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

Nilai properti ini sama untuk aplikasi yang berasal dari vendor yang sama yang berjalan di perangkat yang sama. Nilai yang berbeda dikembalikan untuk aplikasi pada perangkat yang sama yang berasal dari vendor yang berbeda, dan untuk aplikasi pada perangkat yang berbeda terkait dengan vendor.

Tersedia di iOS 6.0 dan yang lebih baru dan dinyatakan dalam UIDevice.h

Untuk iOS 5 lihat tautan ini UIDevice-with-UniqueIdentifier-for-iOS-5

Mahendra Liya
sumber
4

Menggunakan SSKeychain dan kode yang disebutkan di atas. Berikut kode untuk disalin / tempel (tambahkan modul 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;

}

Komposr
sumber
3

Kode berikut membantu mendapatkan UDID:

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

Ini adalah kode yang saya gunakan untuk mendapatkan ID untuk iOS 5 dan 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];
}
Grzegorz Krukowski
sumber
Apa yang Anda lakukan tentang peringatan kompiler PerformSelector may cause a leak because its selector is unknown?
Basil Bourque
Anda tidak dapat lagi menggunakan advertisingIdentifier untuk tujuan ini karena Apple akan menolaknya. Info lebih lanjut: techcrunch.com/2014/02/03/...
codeplasma
2

Dari iOS 6 dan seterusnya, kami memiliki NSUUIDkelas yang sesuai dengan RFC4122

Tautan Apple: apple_ref untuk NSUUID

Dshah
sumber
2

iOS 11 telah memperkenalkan kerangka kerja DeviceCheck. Ini memiliki solusi fullproof untuk mengidentifikasi perangkat secara unik.

Santosh Botre
sumber
1

Cara kerja untuk mendapatkan UDID:

  1. Luncurkan server web di dalam aplikasi dengan dua halaman: satu harus mengembalikan profil MobileConfiguration yang dibuat khusus dan yang lain harus mengumpulkan UDID. Info lebih lanjut di sini , di sini dan di sini .
  2. Anda membuka halaman pertama di Mobile Safari dari dalam aplikasi dan itu mengarahkan Anda ke Settings.app yang meminta untuk menginstal profil konfigurasi. Setelah Anda menginstal profil, UDID dikirim ke halaman web kedua dan Anda dapat mengaksesnya dari dalam aplikasi. (Settings.app memiliki semua hak yang diperlukan dan aturan kotak pasir yang berbeda).

Contoh menggunakan 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)
    }
}

Berikut isinya 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>

Instalasi profil akan gagal (saya tidak repot-repot menerapkan respons yang diharapkan, lihat dokumentasi ), tetapi aplikasi akan mendapatkan UDID yang benar. Dan Anda juga harus menandatangani mobileconfig .

bzz
sumber
1

Untuk Swift 3.0 silakan gunakan kode di bawah ini.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Ganesha
sumber
1
iOS 11 telah memperkenalkan kerangka kerja DeviceCheck. Ini memiliki solusi fullproof untuk mengidentifikasi perangkat secara unik.
Santosh Botre
1

Kamu bisa menggunakan

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

Yang unik untuk perangkat di semua aplikasi.

Dhaval
sumber
0

Jika seseorang menemukan pertanyaan ini, ketika mencari alternatif. Saya telah mengikuti pendekatan ini di IDManagerkelas, Ini adalah kumpulan dari solusi yang berbeda. KeyChainUtil adalah pembungkus untuk dibaca dari gantungan kunci. Anda juga dapat menggunakan hashed MAC addresssebagai jenis ID unik.

/*  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;
}
karim
sumber
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;
}
mahesh chowdary
sumber
0

Kita dapat menggunakan identifierForVendor untuk 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;
}

--Catatan penting ---

UDID dan identifierForVendor berbeda: ---

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.
Pengembang HD
sumber
apakah kamu yakin bisakah kita menggunakan identifierForVendor untuk ios7 ,?
Avis
0

Apple telah menyembunyikan UDID dari semua API publik, dimulai dengan iOS 7. UDID apa pun yang dimulai dengan FFFF adalah ID palsu. Aplikasi "Kirim UDID" yang sebelumnya berfungsi tidak dapat lagi digunakan untuk mengumpulkan UDID untuk perangkat uji. (mendesah!)

UDID ditampilkan ketika perangkat terhubung ke XCode (dalam agenda), dan ketika perangkat terhubung ke iTunes (meskipun Anda harus mengklik 'Serial Number' untuk mendapatkan Pengenal untuk ditampilkan.

Jika Anda perlu mendapatkan UDID agar perangkat ditambahkan ke profil bawaan, dan tidak bisa melakukannya sendiri di XCode, Anda harus mengikuti langkah-langkah untuk menyalin / menempelkannya dari iTunes.

Apakah ada cara sejak (rilis iOS 7) untuk mendapatkan UDID tanpa menggunakan iTunes di PC / Mac?

Preet
sumber
0

Saya juga punya masalah, dan solusinya sederhana:

    // 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;
Ahmet Kazim Günay
sumber
0

Alternatif yang tidak sempurna tetapi salah satu yang terbaik dan terdekat dari UDID (di Swift menggunakan iOS 8.1 dan Xcode 6.1):

Menghasilkan UUID acak

let strUUID: String = NSUUID().UUIDString

Dan gunakan perpustakaan KeychainWrapper :

Tambahkan nilai string ke gantungan kunci:

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

Ambil nilai string dari gantungan kunci:

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

Hapus nilai string dari gantungan kunci:

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

Solusi ini menggunakan gantungan kunci, sehingga catatan yang disimpan dalam gantungan kunci akan bertahan, bahkan setelah aplikasi dihapus dan diinstal ulang. Satu-satunya cara menghapus catatan ini adalah dengan Reset semua konten dan pengaturan perangkat. Itulah mengapa saya menyebutkan bahwa solusi substitusi ini tidak sempurna tetapi tetap merupakan salah satu solusi terbaik pengganti UDID di iOS 8.1 menggunakan Swift.

Raja-Penyihir
sumber
0

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

Ankit garg
sumber