web-dev-qa-db-ja.com

デバイスのiOSアプリをアンインストールした後、iOSでidentifierForVendorを保持する方法は?

ログインのためにWebサービスを呼び出すiOSアプリを開発していますが、その時点でログイン資格情報をベンダー識別子(identifierForVendor)とともにWebサーバーに送信し、それらの資格情報に対してデバイスを一意に識別します。 。

IdentifierForVendorを取得しました

NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString

この識別子は、ウェブサーバーのデータベースとデバイスデータベースに保存されます。次回ユーザーがアプリケーションを開き、ウェブサーバーからデータをダウンロードしようとすると、まずユーザーデバイスのローカルidentifierForVendorがウェブサーバーに保存された識別子と比較されます。

ユーザーがアプリをアンインストールして再インストールすると問題が発生し、identifierForVendorが変更されていることがわかりました。そのため、ユーザーはこれ以上先に進むことができません。

Apple documentation IDevice Documentation

そこに記載されているように、同じベンダーのすべてのアプリがデバイスからアンインストールされた場合、そのベンダーのアプリの新規インストール時に新しいidentifierForVendorが使用されます。

私の場合、これにどう対処するのですか?

65
Harshavardhan

あなたはKeyChainでそれを保持することができます

-(NSString *)getUniqueDeviceIdentifierAsString
{

 NSString *appName=[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];

 NSString *strApplicationUUID = [SSKeychain passwordForService:appName account:@"incoding"];
 if (strApplicationUUID == nil)
 {
    strApplicationUUID  = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [SSKeychain setPassword:strApplicationUUID forService:appName account:@"incoding"];
 }

 return strApplicationUUID;
}
63
nerowolfe

通常、identifierForVendorは使用しないでください。代わりに、NSUUIDを使用してカスタムUUIDを生成し、それをキーチェーンに保存します(アプリを削除して再インストールしてもキーチェーンは削除されないため)。

19
Wain

@nerowolfeの answer に追加。

SSKeychainは、デフォルトの同期モードとしてkSecAttrSynchronizableAnyを使用します。おそらくidentifierForVendorを複数のデバイス間で同期させたくないので、ここにコードを示します。

// save identifierForVendor in keychain without sync
NSError *error = nil;
SSKeychainQuery *query = [[SSKeychainQuery alloc] init];
query.service = @"your_service";
query.account = @"your_account";
query.password = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
query.synchronizationMode = SSKeychainQuerySynchronizationModeNo;
[query save:&error];
9
griga13

KeyChainを使用してVendorIdentifierを保存してみてください。アプリをアンインストールしても、デバイスがリセットされるまで存在します。

5
iphonic

OK。私はサードパーティ、つまりSSKeychainを使いたくありませんでした。だからこれは私が試したコードで、かなりシンプルでうまく機能しています:

    NSString *bundleId = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:bundleId accessGroup:nil];
if(![keychainItem objectForKey:(__bridge id)(kSecValueData)]){
    NSString *idfa = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [keychainItem setObject:idfa forKey:(__bridge id)(kSecValueData)];
    NSLog(@"saving item %@", [keychainItem objectForKey:(__bridge id)(kSecValueData)]);
}else{
    NSLog(@"saved item is %@", [keychainItem objectForKey:(__bridge id)(kSecValueData)]);
}
4
Gautam Jain

迅速なバージョン

func UUID() -> String {

    let bundleName = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String
    let accountName = "incoding"

    var applicationUUID = SAMKeychain.passwordForService(bundleName, account: accountName)

    if applicationUUID == nil {

        applicationUUID = UIDevice.currentDevice().identifierForVendor!.UUIDString

        // Save applicationUUID in keychain without synchronization
        let query = SAMKeychainQuery()
        query.service = bundleName
        query.account = accountName
        query.password = applicationUUID
        query.synchronizationMode = SAMKeychainQuerySynchronizationMode.No

        do {
            try query.save()
        } catch let error as NSError {
            print("SAMKeychainQuery Exception: \(error)")
        }
    }

    return applicationUUID
}
3
Michael Kalinin

一意の番号をデバイスにリンクする明確な方法はもうありません。これはAppleプライバシーガイドラインでは許可されていません。

キーチェーンに独自の一意のIDを保存することもできますが、ユーザーがデバイスをクリアすると、このIDもなくなります。

デバイスをユーザーにリンクする が一般的に間違っているのは、ユーザーではなくデバイスを識別するためです。そのため、ユーザーが再ログインでき、ベンダーIDがユーザーアカウントにバインドされるように、APIを変更する必要があります。

また、ユーザーがiPhoneやiPadなどのデバイスを複数持ち、両方でアプリを使用するとどうなりますか?認証は一意のIDに基づいているため、これは実行できません。

2
rckoenes

この問題には KeychainAccess podを使用していました。

ポッドファイルで:

pod 'KeychainAccess', '~> 2.4' //If you are using Swift 2.3 
pod 'KeychainAccess' //Defaults to 3.0.1 which is in Swift 3

キーチェーンでUUIDを設定するファイルにKeychainAccessモジュールをインポートします

import KeychainAccess

以下のコードを使用して、キーチェーンからUUIDを設定および取得します。

注:BundleIdはキーでUUIDは値です

var bundleID = NSBundle.mainBundle().bundleIdentifier
    var uuidValue = UIDevice.currentDevice().identifierForVendor!.UUIDString

 //MARK: - setVenderId and getVenderId
    func setVenderId() {

        let keychain = Keychain(service: bundleID!)

        do {
            try keychain.set(venderId as String, key: bundleID!)
            print("venderId set : key \(bundleID) and value: \(venderId)")
        }
        catch let error {
            print("Could not save data in Keychain : \(error)")
        }
    }

    func getVenderId() -> String {
        let keychain = Keychain(service: bundleID!)
        let token : String = try! keychain.get(bundleID!)!
        return token
    }
1