تحميل - xcode ios 12




UIDevice uniqueIdentifier موقوف-ماذا تفعل الآن؟ (20)

أضافت Apple إطار عمل جديد في نظام iOS 11 يسمى DeviceCheck والذي سيساعدك في الحصول على المعرف الفريد بسهولة كبيرة. قراءة هذا النموذج مزيد من المعلومات. https://medium.com/@santoshbotre01/unique-identifier-for-the-ios-devices-590bb778290d

لقد اتضح أن خاصية UIDevice uniqueIdentifier تم إيقافها في iOS5 وما فوق. لا يبدو أن هناك طريقة أو خاصية بديلة متاحة أو قادمة.

تعتمد العديد من تطبيقاتنا الحالية بشكل كبير على هذه الخاصية لتحديد جهاز معين بشكل فريد. هل يمكن لأي شخص أن يقترح أي أفكار حول كيفية التعامل مع هذه المشكلة في المستقبل؟

اقتراح من الوثائق هو ...

إعتبارات خاصة

لا تستخدم الخاصية uniqueIdentifier. لإنشاء معرف فريد خاص بتطبيقك ، يمكنك استدعاء الدالة CFUUIDCreate لإنشاء UUID ، NSUserDefaults في قاعدة البيانات الافتراضية باستخدام فئة NSUserDefaults .

ومع ذلك ، لن تكون هذه القيمة مماثلة إذا قام المستخدم بإلغاء تثبيت التطبيق وإعادة تثبيته.


أنا متأكد من أن أبل قد أزعجت العديد من الناس مع هذا التغيير. أقوم بتطوير تطبيق مسك الدفاتر لنظام iOS ولدي خدمة عبر الإنترنت لمزامنة التغييرات التي تم إجراؤها على الأجهزة المختلفة. تحتفظ الخدمة بقاعدة بيانات لجميع الأجهزة والتغييرات التي تحتاج إلى نشرها. لذلك من المهم معرفة الأجهزة التي هي. أنا تتبع الأجهزة باستخدام UIDevice uniqueIdentifier ولما يستحق ، وهنا أفكاري.

  • توليد UUID وتخزينها في افتراضيات المستخدم؟ ليس جيدًا لأن هذا لا يستمر عند حذف المستخدم للتطبيق. إذا تم تثبيتها مرة أخرى في وقت لاحق ، يجب ألا تنشئ الخدمة عبر الإنترنت سجلًا جديدًا للأجهزة ، مما يؤدي إلى إضاعة الموارد على الخادم وإعطاء قائمة بالأجهزة التي تحتوي على الجهاز نفسه مرتين أو أكثر. سيشاهد المستخدمون أكثر من "iPhone's Bob" مدرجة إذا أعادوا تثبيت التطبيق.

  • توليد UUID وتخزينها في keychain؟ كانت هذه خطتي ، حيث استمرت حتى عند إلغاء تثبيت التطبيق. ولكن عند استعادة نسخة احتياطية من iTunes إلى جهاز iOS جديد ، يتم نقل keychain إذا تم تشفير النسخة الاحتياطية. يمكن أن يؤدي ذلك إلى وجود جهازين يحتويان على نفس معرف الجهاز إذا كانت الأجهزة القديمة والجديدة كليهما في الخدمة. يجب إدراج هذه الأجهزة كجهازين في الخدمة عبر الإنترنت ، حتى إذا كان اسم الجهاز هو نفسه.

  • توليد تجزئة عنوان MAC ومعرف الحزمة؟ هذا يبدو وكأنه أفضل حل لما أحتاجه. من خلال التجزئة باستخدام معرّف الحزمة ، لن يتمكن معرف الجهاز الذي تم إنشاؤه من تمكين تتبع الجهاز عبر التطبيقات واحصل على معرف فريد للتطبيق + الجمع بين الجهاز.

من المثير للاهتمام ملاحظة أن وثائق Apple الخاصة تشير إلى التحقق من صحة إيصالات Mac App Store من خلال حساب تجزئة لعنوان MAC للنظام بالإضافة إلى معرف الحزمة والإصدار. لذلك يبدو هذا مسموحًا به من خلال السياسة ، سواء كان يمر عبر مراجعة التطبيق التي لا أعرفها بعد.


إذا تعثر أحدهم على هذا السؤال ، عند البحث عن بديل. لقد اتبعت هذا النهج في فئة IDManager ، وهذا هو مجموعة من حلول مختلفة. KeyChainUtil هو المجمع لقراءة من keychain. يمكنك أيضًا استخدام hashed MAC address كنوع من المعرّف الفريد.

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

استنادًا إلى الرابط الذي اقترحهmoonlight ، أجريت عدة اختبارات ويبدو أنها أفضل حل. كما يقولDarkDust الطريقة تذهب للتحقق من en0 التي تتوفر دائما.
هناك خياران:
uniqueDeviceIdentifier (MD5 of MAC + CFBundleIdentifier)
و uniqueGlobalDeviceIdentifier (MD5 من MAC) ، هذه دائماً إرجاع نفس القيم.
أسفل الاختبارات التي قمت بها (مع الجهاز الحقيقي):

#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 - (وضع AirPlane) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (وضع AirPlane) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) بعد إزالة وإعادة تثبيت التطبيق XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) بعد إزالة التطبيق وتثبيته

آمل أن يكون مفيدا.

تصحيح:
كما أشار آخرون ، لم يعد هذا الحل في iOS 7 مفيدًا نظرًا لأن uniqueIdentifier لم يعد متاحًا ، كما أن البحث عن عنوان MAC يرجع الآن غالبًا إلى 02: 00: 00: 00: 00: 00



تحقق من هذا،

يمكننا استخدام Keychain بدلاً من فئة NSUserDefaults ، لتخزين UUID تم إنشاؤه بواسطة CFUUIDCreate .

بهذه الطريقة يمكننا تجنب استخدام UUID مع إعادة التثبيت ، والحصول على نفس UUID دائمًا لنفس التطبيق حتى إلغاء تثبيت المستخدم وإعادة تثبيته مرة أخرى.

سيتم إعادة إنشاء UUID فقط عند إعادة ضبط الجهاز بواسطة المستخدم.

حاولت هذه الطريقة مع SFHFKeychainUtils وانها تعمل مثل السحر.


قد ترغب في النظر في استخدام OpenUDID والذي يعد بديلًا لاستبدال UDID .

بشكل أساسي ، لمطابقة UDID ، يلزم توفر الميزات التالية:

  1. فريدة أو فريدة بما فيه الكفاية (من المحتمل أن يكون احتمال حدوث تصادم منخفض مقبولًا جدًا)
  2. استمرار عبر إعادة تمهيد ، ويعيد ، ويزيل
  3. متاحة عبر تطبيقات البائعين المختلفين (مفيدة لاكتساب المستخدمين عبر شبكات CPI) -

ويفي OpenUDID بما سبق OpenUDID الاشتراك" المدمجة ليتم النظر فيها لاحقًا.

تحقق من http://OpenUDID.org أنه يشير إلى GitHub المقابلة. أتمنى أن يساعدك هذا!

كملاحظة جانبية ، أود أن نخجل من أي عنوان MAC البديل. في حين أن عنوان MAC يبدو كحل مغر وشامل ، تأكد من أن هذه الفاكهة المعلقة منخفضة السموم. يعتبر عنوان MAC حساسًا للغاية ، وقد تقوم Apple بإيقاف الوصول إلى هذا الجهاز بشكل جيد قبل أن تتمكن حتى من قول "إرسال هذا التطبيق" ... يستخدم عنوان شبكة MAC لمصادقة أجهزة معينة على الشبكات الخاصة (WLAN) أو غيرها من الخدمات الافتراضية الخاصة الشبكات (الشبكات الخاصة الافتراضية). .. إنه أكثر حساسية من UDID السابق!


قد يساعد: استخدام التعليمات البرمجية أدناه سوف تكون دائما فريدة من نوعها باستثناء مسحتك (تنسيق) جهازك.

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

لا تستخدم هذه المكتبات - libOmnitureAppMeasurement ، فهي تستخدم uniqueIdentifier الذي لا يدعمه أي شخص بعد الآن


لقد قدم نظام التشغيل iOS 11 إطار عمل DeviceCheck. لديها حل fullproof لتحديد الجهاز بشكل فريد.


يبدو أنه بالنسبة إلى نظام التشغيل iOS 6 ، توصي Apple باستخدام طبقة NSUUID .

من الرسالة الآن في مستندات uniqueIdentifier لموقع uniqueIdentifier :

موقوف في iOS 5.0. استخدم خاصية identifierForVendor لهذه الفئة أو خاصية advertisingIdentifier الخاصة بفئة ASIdentifierManager بدلاً من ذلك ، كما هو مناسب ، أو استخدم طريقة UUID لفئة NSUUID لإنشاء UUID وكتابتها في قاعدة بيانات المستخدم الافتراضية.


يساعد الرمز التالي للحصول على UDID:

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

يمكن انتحال عنوان MAC مما يجعل مثل هذا النهج عديم الفائدة لربط المحتوى بمستخدمين محددين أو تنفيذ ميزات الأمان مثل القوائم السوداء.

بعد بعض الأبحاث الإضافية يبدو لي أننا غادرنا دون بديل مناسب حتى الآن. أنا آمل بجدية أن تفكر آبل في قرارهم.

ربما يكون من الأفضل إرسال بريد إلكتروني إلى Apple حول هذا الموضوع و / أو تقديم طلب خلل / ميزة على ذلك ، نظرًا لأنهم ربما ليسوا على دراية بالعواقب الكاملة للمطورين.


يمكنك استخدام

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

وهو فريد للجهاز في كل التطبيقات.



UIDevice identifierForVendor تقديمه في iOS 6 لأغراضك.

identifierForVendor عبارة عن سلسلة أبجدية رقمية تحدد بشكل فريد جهازًا لمورّد التطبيق. (يقرأ فقط)

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

قيمة هذه الخاصية هي نفسها للتطبيقات التي تأتي من نفس البائع الذي يعمل على نفس الجهاز. يتم إرجاع قيمة مختلفة للتطبيقات على نفس الجهاز الذي يأتي من مورِّدين مختلفين ، وبالنسبة للتطبيقات على أجهزة مختلفة ، فإن البائع يتعامل مع الأجهزة المختلفة.

متوفر في iOS 6.0 والإصدارات الأحدث ويتم الإعلان عنه في UIDevice.h

بالنسبة إلى iOS 5 ، قم بالرجوع إلى هذا الرابط github


A working way to get UDID:

  1. Launch a web server inside the app with two pages: one should return specially crafted MobileConfiguration profile and another should collect UDID. More info here , here and here .
  2. You open the first page in Mobile Safari from inside the app and it redirects you to Settings.app asking to install configuration profile. After you install the profile, UDID is sent to the second web page and you can access it from inside the app. (Settings.app has all necessary entitlements and different sandbox rules).

An example using 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)
    }
}

Here are the contents of 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>

ستفشل عملية تثبيت الملف الشخصي (لم أكن عناء تنفيذ استجابة متوقعة ، راجع documentation ) ، ولكن سيحصل التطبيق على UDID صحيح. ويجب عليك أيضًا التوقيع على mobileconfig .


Apple has hidden the UDID from all public APIs, starting with iOS 7. Any UDID that begins with FFFF is a fake ID. The "Send UDID" apps that previously worked can no longer be used to gather UDID for test devices. (sigh!)

The UDID is shown when a device is connected to XCode (in the organizer), and when the device is connected to iTunes (although you have to click on 'Serial Number' to get the Identifier to display.

If you need to get the UDID for a device to add to a provisioning profile, and can't do it yourself in XCode, you will have to walk them through the steps to copy/paste it from iTunes.

Is there a way since (iOS 7's release) to get the UDID without using iTunes on a PC/Mac?



We can use identifierForVendor for 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;
}

--Important Note ---

UDID and identifierForVendor are different:---

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.




deprecated