2016-09-15 9 views
5

आईओएस 10 में मेरे ऐप की क्लाउडकिट सुविधाएं अब और काम नहीं करती हैं। सटीक वही ऐप आईओएस 9 पर ठीक काम करता है। मैंने एक्सकोड 8 में निर्माण करने की कोशिश की और यह अभी भी काम नहीं करता है।क्लाउडकिट त्रुटि: फ़ील्ड एन्क्रिप्टेड के लिए एन्क्रिप्टेड डेटा को अनचाहे करने के लिए पीसीएस ऑब्जेक्ट नहीं मिल सका PublicSharingKey

वह कोड जो काम नहीं करता है, और जो त्रुटि उत्पन्न करता है, नीचे दिखाया गया है। हम क्या करते हैं सार्वजनिक क्लाउड डेटाबेस से एक रिकॉर्ड मिलता है। मैंने पुष्टि की है कि डिवाइस पर एक नया iCloud खाता है। उसी डिवाइस ने आईओएस 9 के तहत ऐप के साथ पूरी तरह से काम किया। मैंने डिवाइस को पुनरारंभ करने और आईक्लाउड में साइन इन करने और आउट करने का प्रयास किया, लेकिन फिर भी वही त्रुटि मिल गई। (पाया समाधान)

Error: <CKError 0x15e7c2b0: "Internal Error" (1/5001); "Couldn't get a 
PCS object to unwrap encrypted data for field 
encryptedPublicSharingKey: (null)"> 

उत्तर

2

मैं कई हफ्तों तक इस मुद्दे पर ऐप्पल की डेवलपर तकनीकी सहायता टीम के साथ संचार में रहा हूं। @ Ewcy के उत्तर के रूप में, समस्या लघु GUID संपत्ति से संबंधित है। मैंने इसे सही उत्तर के रूप में सेट किया होगा, हालांकि, इसके मुकाबले इसमें कुछ और है।

आईओएस 10.0.2 के रूप में, यदि रिकॉर्ड सार्वजनिक डेटाबेस में है, और यह लघु GUID विकल्प चेक किया गया है, तो निम्न त्रुटि जब एक iOS 10 डिवाइस रिकॉर्ड लाने की कोशिश करता है का सामना करना पड़ा हो जाएगा :

CKError 0x15e7c2b0: "Internal Error" (1/5001); "Couldn't get a PCS object to unwrap encrypted data for field encryptedPublicSharingKey: (null)"

लेकिन अगर रिकॉर्ड निजी डेटाबेस (चाहे वह एक कस्टम क्षेत्र या डिफ़ॉल्ट क्षेत्र में है की परवाह किए बिना) में है, तो यह एक लघु GUID है और अभी भी कर सकते हैं आईओएस 10 पर ठीक दिलवाया जा

ऐप्पल ने मुझे बताया है कि सार्वजनिक डीबी से लघु GUID के साथ रिकॉर्ड लाने में असमर्थता आईओएस 10 में एक बग है और मुझे यकीन है कि वे कुछ भविष्य के अपडेट में ठीक हो जाएंगे। वे मुझे नहीं बता सके, हालांकि, यह तय होने तक कितना समय लगेगा।

वर्कअराउंड: तो, कम से कम अभी तक, वर्कअराउंड (जो @ewcy भी उल्लेख किया गया है) छोटे GUID विकल्प के बिना आपके सार्वजनिक डेटाबेस में सभी रिकॉर्ड्स को फिर से बनाना है। जिस तरह से मैंने क्लाउडकिट डैशबोर्ड में सीधे रिकॉर्ड बनाने के लिए किया था। जिस तरह से @ewcy ने जावास्क्रिप्ट का उपयोग किया था। आप इसे उद्देश्य सी में भी कर सकते हैं, जैसा कि मैंने नीचे दिए गए कोड उदाहरण में दिखाया है। अंत में, आप इसे स्विफ्ट में कर सकते हैं (विशेष रूप से यदि आप विस्मयादिबोधक चिह्न और प्रश्न चिह्न बहुत पसंद करते हैं !!! ?? !!?! 1)।

लघु GUID संपत्ति क्लाउडकिट की नई साझाकरण सुविधाओं से संबंधित है जो आईओएस 10 में पेश की गई थीं। यदि आप प्रोग्राम्सिक रूप से एक सीकेआरकॉर्ड में सीकेशेयर जोड़ते हैं (जिसे केवल निजी डेटाबेस में कस्टम क्षेत्र में रिकॉर्ड पर किया जा सकता है, जब तक कि आप अपने ऐप को क्रैश नहीं करना चाहते हैं ... हे) तो वह रिकॉर्ड स्वचालित रूप से एक लघु GUID प्राप्त होगा।आप नीचे नमूना कोड के साथ इसका परीक्षण कर सकते हैं।

बग शायद इस तथ्य से आता है कि सार्वजनिक डीबी रिकॉर्ड साझा नहीं किए जा सकते हैं, इसलिए उनका encryptedPublicSharingKey शून्य क्यों है। लेकिन ऐप्पल के एपीआई के पर्दे के पीछे देखने में सक्षम होने के बावजूद, यह सुनिश्चित करना मुश्किल है कि सटीक कारण क्या है।

ऐप्पल के डेवलपर टेक सपोर्ट व्यक्ति जिसने मुझे इस मामले में मदद की, मुझे बताया कि उन्हें किसी भी रिकॉर्ड पर शॉर्ट GUID सेट करने का विकल्प भी नहीं होना चाहिए, जिसके लिए सार्वजनिक डेटाबेस में उन रिकॉर्ड की तरह साझा करना असंभव है। यह विकल्प भी है कि यहां तक ​​कि विकल्प भी है।

बेशक, जब हम में से अधिकांश डेवलपर्स "लघु GUID" देखते हैं, तो हम सोचते हैं, "GUID अच्छे हैं, मैं बेहतर उस बॉक्स को चेक करता हूं! उस GUID को बाद में चाहिए!" मेरा मतलब है, कौन GUID प्यार नहीं करता, अमीरात? _ (ツ) _/¯


यह भी ध्यान रखें वहाँ आईओएस 10 पर एक अलग बग अगर iCloud ड्राइव सक्षम नहीं है जहां है, या कोई भी डिवाइस पर iCloud में हस्ताक्षर किए है, तो मूल रूप से CloudKit में कुछ भी करने से कि विफल रहता है (लेकिन विभिन्न त्रुटि संदेशों के साथ)। आईओएस 9 पर सभी चीजें ठीक काम करती हैं।

शायद हम आईओएस 10.1 में इन सभी समस्याओं के कुछ अपडेट देखेंगे? तथ्य यह है कि क्लाउडकिट आंशिक रूप से आईओएस 10 पर टूट गया है और अब एक महीने से अधिक समय से रहा है। मुझे एहसास है कि मुझे इस टिप्पणी में संपादकीयकरण नहीं करना चाहिए, इसलिए मैं नहीं करूंगा, लेकिन बस कहता हूं कि मैं बहुत संयम दिखा रहा हूं। अलग करने के लिए कब और कहाँ समस्या वास्तव में होंगे (भी अन्य आईओएस 10 CloudKit कीड़े कि मैंने कहा, अगर आप iCloud ड्राइव बंद कर दिया है का पता चलता है या आप डिवाइस पर iCloud में प्रवेश नहीं किया है


नमूना कोड):

// 
// AppDelegate.m 
// 

#import "AppDelegate.h" 
#import <CloudKit/CloudKit.h> 

#define LOG(__FORMAT__, ...) NSLog(@"\n\n" __FORMAT__ @"\n\n", ##__VA_ARGS__) 

@interface AppDelegate() 

@end 

@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
    CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase]; 

    /* First create public testRecord_noGuid with no Short GUID, and testRecord_withGuid with a Short GUID, in the CloudKit Dashboard. Then run this code. */ 

    /* Try to fetch the one without a Short GUID. */ 

    CKRecordID *testRecordID_noGuid = [[CKRecordID alloc] initWithRecordName:@"testRecord_noGuid"]; 
    [publicDatabase fetchRecordWithID:testRecordID_noGuid completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
     if(error != nil) { 
      LOG(@"<ERROR> Error fetching testRecord_noGuid from public default DB. Error: %@",error); 
      return; 
     } 
     /* This is where we end up on iOS 9 or 10. */ 
     NSDictionary *middle = [record dictionaryWithValuesForKeys:record.allKeys]; 
     LOG(@"<NOTICE> testRecord_noGuid fetched from public default zone: %@",middle); 
    }]; 

    /* Try to fetch the one with a Short GUID. */ 

    CKRecordID *testRecordID_withGuid = [[CKRecordID alloc] initWithRecordName:@"testRecord_withGuid"]; 
    [publicDatabase fetchRecordWithID:testRecordID_withGuid completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
     if(error != nil) { 
      /* This is where we always end up on iOS 10. */ 
      LOG(@"<ERROR> Error fetching testRecord_withGuid from public default zone. Error: %@",error); 
      return; 
     } 
     /* This is where we end up on iOS 9. */ 
     NSDictionary *middle = [record dictionaryWithValuesForKeys:record.allKeys]; 
     LOG(@"<NOTICE> testRecord_withGuid fetched from public default zone: %@",middle); 
    }]; 

    /* The below code demonstrates the issue does not affect private records in custom zones. 
     First time you run this, do it while logged into your developer AppleID with permissions to create a new zone. 
     That way you can login to CloudKit dashboard and verify whether the created records have a Short GUID or not. 
    */ 

    CKDatabase *privateDB = [[CKContainer defaultContainer] privateCloudDatabase];  
    CKRecordZone *testRecordZone = [[CKRecordZone alloc] initWithZoneName:@"TestRecordZone"]; 

    /* Create a new zone */ 

    [privateDB saveRecordZone:testRecordZone completionHandler:^(CKRecordZone * _Nullable zone, NSError * _Nullable error) { 
     if(error != nil) { 
      LOG(@"<ERROR> Error saving private custom zone. Error: %@", error); 
      [self checkPrivateRecordCreationInZone:testRecordZone]; // This will only work if the zone was already created. 
      return; 
     } 
     LOG(@"<NOTICE> Saving of TestRecordZone succeeded. Proceeding to create records in it."); 
     /* Now that the new zone is created, create a test record without a Short GUID */ 
     [self checkPrivateRecordCreationInZone:zone]; 
    }]; 


    /* Uncomment this and run it if the testRecordZone is already created and now you are testing from an 
     AppleID without any perms. */ 
    [self checkPrivateRecordCreationInZone:testRecordZone]; 

    /* Run this to see how it works int he default zone */ 
    //[self checkPrivateRecordCreationInZone:[CKRecordZone defaultRecordZone]]; 

    return YES; 
} 

- (void)checkPrivateRecordCreationInZone:(CKRecordZone *)zone { 
    CKDatabase *privateDB = [[CKContainer defaultContainer] privateCloudDatabase];  
    CKRecordID *testRecordID_noGuid_private = [[CKRecordID alloc] initWithRecordName:@"testRecord_noGuid" zoneID:zone.zoneID]; 
    CKRecord *testRecord_noGuid_private = [[CKRecord alloc] initWithRecordType:@"TestRecordType" recordID:testRecordID_noGuid_private]; 
    [testRecord_noGuid_private setValue:@"foo" forKey:@"bar"]; 
    [privateDB saveRecord:testRecord_noGuid_private completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
     if(error != nil) { 
      if([error.userInfo[@"ServerErrorDescription"] containsString:@"already exists"]) { 
       record = error.userInfo[@"ServerRecord"]; 
       LOG(@"<NOTICE> Record with no Short GUID already existed in private zone: %@",record); 
      } 
      else { 
       if(error.userInfo[@"CKRetryAfter"] != nil) { 
        /* Retry after three seconds :D */ 
        double delay = [error.userInfo[@"CKRetryAfter"] doubleValue] + 0.1; 
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
         [self checkPrivateRecordCreationInZone:zone]; 
        }); 
       } 
       LOG(@"<ERROR> Error saving record with no Short GUID to private custom zone. Error: %@", error); 
       return; 
      } 
     } 
     else { 
      LOG(@"<NOTICE> Created new record with no Short GUID in private custom zone: %@",record); 
     } 

     /* Now that we successfully created a record without a short GUID to the private store, fetch it. */ 

     [privateDB fetchRecordWithID:testRecordID_noGuid_private completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
      if(error != nil) { 
       LOG(@"<ERROR> Error fetching testRecord_noGuid from private custom zone: %@",error); 
       return; 
      } 
      LOG(@"<NOTICE> Successfully fetched testRecord_noGuid from private custom zone: %@",record); 
     }]; 

    }]; 

    /* On iOS 10 or later we can create a private record with a share to force it to have a Short GUID. 
     On iOS 9 or earlier you have to manually create the private record with Short GUID after running 
     the test once to create the TestCustomZone and the private record with no Short GUID. */ 

    CKRecordID *testRecordID_withGuid_private = [[CKRecordID alloc] initWithRecordName:@"testRecord_withGuid" zoneID:zone.zoneID]; 
    CKRecord *testRecord_withGuid_private = [[CKRecord alloc] initWithRecordType:@"TestRecordType" recordID:testRecordID_withGuid_private]; 

    if([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion < 10 || [zone isEqual:[CKRecordZone defaultRecordZone]]) { 
     [privateDB fetchRecordWithID:testRecordID_withGuid_private completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
      if(error != nil) { 
       LOG(@"<ERROR> Error fetching testRecord_withGuid from private custom zone: %@",error); 
       return; 
      } 
      LOG(@"<NOTICE> Successfully fetched testRecord_withGuid from private custom zone: %@",record); 
     }]; 

     return; 
    } 

    /* Create a test record with a Short GUID */ 

    [testRecord_withGuid_private setValue:@"foo" forKey:@"bar"]; 

    CKShare *meForceGuidToExistMuhahaha = [[CKShare alloc] initWithRootRecord:testRecord_withGuid_private]; 
    //meForceGuidToExistMuhahaha.publicPermission = CKShareParticipantPermissionNone; 
    CKModifyRecordsOperation *save = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:@[meForceGuidToExistMuhahaha,testRecord_withGuid_private] 
                      recordIDsToDelete:nil]; 
    save.savePolicy = CKRecordSaveAllKeys; 

    [save setModifyRecordsCompletionBlock: ^(
     NSArray <CKRecord *> * _Nullable savedRecordArray, 
     NSArray <CKRecordID *> * _Nullable deletedRecordArray, 
     NSError    * _Nullable modifyError 
    ){ 
     CKShare *savedShare; 
     CKRecord *savedRecord; 
     BOOL operationDidFail = NO; 
     if(modifyError != nil) { 
      NSArray *errorsToIgnore = @[@"record to insert already exists",@"Atomic failure"]; 
      NSArray *partialErrors = modifyError.userInfo[@"CKPartialErrors"]; 
      if(partialErrors == nil) { 
       operationDidFail = YES; 
      } 
      else { 
       for(id item in partialErrors) { 
        if([item isKindOfClass:[NSError class]]) { 
         NSError *partialError = item; 
         NSString *errorDesc = partialError.userInfo[@"ServerErrorDescription"]; 
         if(errorDesc == nil) { 
          operationDidFail = YES; 
          break; 
         } 
         if(NO == [errorsToIgnore containsObject:errorDesc]) { 
          operationDidFail = YES; 
          break; 
         } 
         savedRecord = partialError.userInfo[@"ServerRecord"]; 
        } 
        else { 
         LOG(@"<ERROR> Unexpected %@ encountered in CKPartialErrrors: %@",NSStringFromClass([item class]),item); 
        } 
       } 
      } 
      if(savedRecord == nil) { 
       operationDidFail = YES; 
      } 
     } 
     if(operationDidFail) { 
      LOG(@"<ERROR> Error saving testRecord_withGuid to private custom zone. Error: %@",modifyError); 
      return; 
     } 
     if(savedRecord != nil) { 
      // This could happen if the save policy is not CKRecordSaveAllKeys. 
      LOG(@"<NOTICE> Record already existed on server. Proceeding with fetch. Record: %@",savedRecord); 
     } 
     else { 
      LOG(@"savedRecords: %@",savedRecordArray); 
      savedShare = (CKShare *)savedRecordArray[0]; 
      savedRecord = (CKShare *)savedRecordArray[1]; 
      LOG(@"<NOTICE> Successfully upserted record to private custom zone with share URL: %@",[savedShare.URL absoluteString]); 
     } 
     /* Now that we successfully created a record with a short GUID to the private store, fetch it. */ 

     [privateDB fetchRecordWithID:testRecordID_withGuid_private completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
      if(error != nil) { 
       LOG(@"<ERROR> Error fetching testRecord_withGuid from private custom zone: %@",error); 
       return; 
      } 
      LOG(@"<NOTICE> Successfully fetched testRecord_withGuid from private custom zone: %@",record); 
     }]; 
    }]; 
    [save start]; 
} 

@end 
2

अपडेट::

कृपया सलाह ...

CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase]; 
CKRecordID *myRecordID = [[CKRecordID alloc] initWithRecordName:@"myRecord"]; 
[publicDatabase fetchRecordWithID:myRecordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { 
    if(error != nil) { 
     CLS_LOG(@"<ERROR> Error fetching record. Error: %@",error); 
     return; 
    } 
    //rest of code 
}]; 

में परिणाम मेरी मूल जवाब में मेरे अंक की

कोई भी सही था। सच्चा अपराधी यह है कि मेरे पास सर्वर-टू-सर्वर स्क्रिप्ट से एक रिकॉर्ड बनाया गया था जिसमें "createShortGUID" है (जिसे मैंने here से कॉपी किया है) सत्य पर सेट है। यकीन नहीं है कि ऐसा क्यों हुआ। लेकिन जब तक मैं सभी सर्वर रूप से बनाए गए रिकॉर्ड साफ़ करें, और करने के लिए मेरी स्क्रिप्ट बदलने के लिए:

var json = { 
    operations: [{ 
     operationType: 'forceUpdate', 
     record: { 
      recordType : "heartBeat", 
      //createShortGUID: true, // Comment this away!!!! 
      recordName : "heartBeatRecordName", 
      fields: { 
       dummyField: { value: "dummyValue" }, 
      }, 
     }, 
    }], 
}; 

और फिर अपने सर्वर रिकॉर्ड फिर से पॉप्युलेट, तो iOS एप्लिकेशन फिर से काम करने के लिए शुरू होता है।

enter image description here

मूल जवाब (बुरा अनुमान): createShortGUID CloudKit डैशबोर्ड में रिकॉर्ड के ऊपरी-दाएं पर चेकबॉक्स से मेल खाती है

इन का प्रयास करें, उनमें से एक समस्या हल मेरे लिए। (लेकिन मुझे नहीं पता कि कौन सा।)

  1. कुछ समय के लिए प्रतीक्षा करें। कंटेनर बनाने के बाद मुझे ~ 3 घंटे लग गए।
  2. उत्पादन कंटेनर पर स्विच करने का प्रयास करें। अपनी एंटाइटेलमेंट फ़ाइल में "com.apple.developer.icloud-container-environment" कुंजी और मूल्य "उत्पादन" (केस संवेदनशील) जोड़ें। निर्माण के लिए आपको कुंजी और मूल्य दोनों में सटीक होना चाहिए। https://developer.apple.com/library/content/technotes/tn2415/_index.html
  3. पर और देखें उस डिवाइस के भीतर से एक रिकॉर्ड बनाने का प्रयास करें। मैंने सार्वजनिक डेटाबेस में रिकॉर्ड्स बनाने के लिए सर्वर-टू-सर्वर स्क्रिप्ट का उपयोग किया। ऐसा लगता है कि मैंने उस डिवाइस के भीतर से एक रिकॉर्ड जोड़ा, आईओएस ने अपने अंदर कुछ "निश्चित" किया है।

मेरा पूरे अनुभव ...

  • एक नया कंटेनर 3 घंटे पहले बनाया गया। सार्वजनिक डेटाबेस में सर्वर-टू-सर्वर स्क्रिप्ट पंपिंग रिकॉर्ड प्राप्त कर सकता है। अब मुझे क्लाइंट आईओएस ऐप से रिकॉर्ड्स पढ़ने की जरूरत है।
  • यदि मैं एक सादा सत्य अनुमान के साथ रिकॉर्ड (केवल एकमात्र रिकॉर्ड टाइप) की क्वेरी करता हूं, तो मुझे <CKError 0x174247470: "Internal Error" (1/1000); "Encountered an error fetching records">
  • थोड़ा गुम हो गया। कोई भाग्य नहीं।
  • अगर मैं रिकॉर्ड (अपने सर्वर से सर्वर स्क्रिप्ट के द्वारा बनाई रिकॉर्ड, CloudKit डैशबोर्ड के माध्यम से पुनः प्राप्त की recordID उपयोग करते हुए) मैं <CKError 0x174253590: "Internal Error" (1/5001); "Couldn't get a PCS object to unwrap encrypted data for field encryptedPublicSharingKey: (null)">
  • थोड़ा Google पर मिला लाने। कोई भाग्य नहीं।
  • एहसास है कि यह एक डिवाइस पर मौजूद समस्या हो सकती है क्योंकि डिवाइस लॉग कहते हैं:
    • डिफ़ॉल्ट 00: 09: ०३.१९०७१५ 0800 cloudd [ऑपरेशन 0x1018916d0] ऑपरेशन एक त्रुटि
    साथ कॉलबैक कतार पर खत्म
    • डिफ़ॉल्ट 00: 09: ०३.१९०९८९ 0800 cloudd [ऑपरेशन 0x1018916d0] ऑपरेशन हो रही है प्रवाह एक स्थानीय त्रुटि के कारण नियंत्रित
  • त्रि डिवाइस पर iCloud/iCloud Keychain को सक्षम/अक्षम करने के लिए एड करें। मदद नहीं कर रहा
  • उत्पादन कंटेनर पर स्विच करने का प्रयास किया, मदद नहीं कर रहा है। (मैं भूल गया था कि मैंने एपीएन के लिए "एपीएस एनवायरनमेंट" कुंजी का उपयोग करके गलत तरीके से किया है, जो एपीएन के लिए है और क्लाउडकिट के लिए नहीं है)
  • डिवाइस के भीतर से एक रिकॉर्ड बनाने का प्रयास किया, लिखने ठीक हैं।
  • एक बार फिर उत्पादन कंटेनर पर स्विच करने का प्रयास किया (इस बार शायद सही कुंजी का उपयोग कर)
  • मैजिकल सब कुछ तब से काम करता था।
संबंधित मुद्दे