在本系列的上一教程中 ,您添加了在基于iCloud的购物清单应用程序中创建,更新和删除购物清单的功能。 在该系列的最后一篇教程中,您将使用CKShare与其他用户共享特定的购物清单项目。

在本系列中,您已经使用私有数据库,并且学习了有关公共数据库的知识。 但是,直到2016年WWDC时,Apple推出CKShare为止 ,还没有合适的方法来共享应用程序的数据。 专用数据库仅适用于已登录的用户,而公用数据库则设计用于公用内容,并允许任何人查看记录。 但是,当使用某些Apple自己的iCloud应用程序(例如Pages,Keynote或Notes)时,您可能会注意到通过选择共享按钮,它可以邀请其他用户访问您的数据。

在这篇文章中,我将向您展示如何有选择地共享内容。

iOS 内购 共享秘钥_iOS 内购 共享秘钥

在本教程中,您将为应用程序提供相同的功能,以便用户可以在共享的购物清单项上与您进行协作。

先决条件

请记住,我将使用Xcode 9和Swift3。如果您使用的是Xcode的旧版本,请记住您正在使用其他版本的Swift编程语言。

在本教程中,我们将继续本系列第三篇教程中的内容。 您可以从GitHub下载或克隆项目。

关于数据库

苹果提供三种类型的数据库:公共数据库,私有数据库和共享数据库。 在公共数据库中,您可以在默认区域内提供所有人都可以访问的内容。 用户甚至不需要通过iCloud进行身份验证即可查看内容,但是他们无法编写更改。

您应该已经熟悉私有数据库,因为购物应用程序一直在利用私有数据库来存储公众无法访问的记录。 现在,您所有的购物清单都是私人清单。

共享数据库是Apple进入您的私有数据库的共享数据库窗口,该窗口授予用户通过CKShare进行读取或写入的CKShare 。

这是需要注意的重要的共享数据库驻留在受邀用户的帐户,是一个门户网站的拥有者的专用数据库,与CKShare是一种特定类型CKRecord被连接到CKRecord 。

iOS 内购 共享秘钥_iOS 内购 共享秘钥_02

添加UICloudSharingController

您将首先实现UICloudSharingController及其关联的UICloudSharingControllerDelegate 。 到目前为止,最简单的共享方法是使用UICloudSharingController ,它负责提供和呈现用于共享记录,邀请用户和设置记录权限的屏幕,所有这些只需几行代码。 根据Apple的SDK, UICloudSharingController毫不费力地使您能够:

邀请他人查看或协作共享记录

设置访问权限,确定谁可以访问共享记录(仅限受邀人员或具有共享链接的任何人)

设置一般或个人权限(只读或读/写)

删除一个或多个参与者的访问权限

停止参与(如果用户是参与者)

停止与所有参与者共享(如果用户是共享记录的所有者)

在您的ListViewController.swift文件中,包括UICloudSharingControllerDelegate委托:

class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, 
UICloudSharingControllerDelegate{

接下来,添加TableView的didSelectRowAt:方法,以便当用户选择一个单元格时,它将调用共享表。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let item = items[indexPath.row]
        
        let share = CKShare(rootRecord: item)
        

        if let itemName = item.object(forKey: "name") as? String {
            self.itemName = item.object(forKey: "name") as? String
            share[CKShareTitleKey] = "Sharing \(itemName)" as CKRecordValue?

        } else {
            share[CKShareTitleKey] = "" as CKRecordValue?
            self.itemName = "item"
        }
        
        share[CKShareTypeKey] = "com.doronkatz.List" as CKRecordValue
        prepareToShare(share: share, record: item)
    }

在上面的方法中,创建一个CKShare ,将item CKRecord关联为根记录。 然后,该方法设置share[CKShareTitleKey]和share[CKShareTypeKey]属性,以准备显示共享记录。 该方法最终调用prepareToShare ,传入原始记录以及刚刚创建的共享记录,您将在下一个实现中:

private func prepareToShare(share: CKShare, record: CKRecord){
        
        let sharingViewController = UICloudSharingController(preparationHandler: {(UICloudSharingController, handler: @escaping (CKShare?, CKContainer?, Error?) -> Void) in
   
            let modRecordsList = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil)
            
            modRecordsList.modifyRecordsCompletionBlock = {
                (record, recordID, error) in
                
                handler(share, CKContainer.default(), error)
            }
            CKContainer.default().privateCloudDatabase.add(modRecordsList)
        })
        
        sharingViewController.delegate = self

        sharingViewController.availablePermissions = [.allowReadWrite,
                                                  .allowPrivate]
        self.navigationController?.present(sharingViewController, animated:true, completion:nil)
    }

该方法在通知完成处理程序之前,首先使用CKModifyRecordsOperation将记录CKModifyRecordsOperation到私有云数据库中, UICloudSharingController在块处理程序中创建UICloudSharingController 。 在最终将视图控制器呈现给用户之前,您还需要设置视图控制器的可用权限。

实现UICloudSharingController委托方法

您还需要实现两个强制性委托方法itemTitleForCloudSharingController和failedToSaveShareWithError 。 您还可以选择实现其他可选的委托方法。

func cloudSharingControllerDidSaveShare(_ csc: UICloudSharingController) {
        print("saved successfully")
    }
    
    func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
        print("failed to save: \(error.localizedDescription)")
    }
    
    func itemThumbnailData(for csc: UICloudSharingController) -> Data? {
        return nil //You can set a hero image in your share sheet. Nil uses the default.
    }
    
    func itemTitle(for csc: UICloudSharingController) -> String? {
        return self.itemName
    }

itemTitleForCloudSharingController方法与您先前设置的CKShareTitleKey属性匹配,请求标题显示在邀请列表中。 failedToSaveShareWithError通知failedToSaveShareWithError处理失败的共享请求。 继续构建并运行您的应用程序,创建一条记录,然后选择一条记录以触发共享表。

iOS 内购 共享秘钥_python_03

这看起来不错,但您的工作仍未完成! 您需要处理其他用户如何接收和显示您的共享记录。

接收和处理CKShare记录

最后,您需要将应用程序设置为能够获取和显示共享记录。 打开您的AppDelegate.swift文件,并添加userDidAcceptCloudKitShareWith委托方法:

func application(_ application: UIApplication, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShareMetadata) {
        
        let acceptSharing: CKAcceptSharesOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata])
        
        acceptSharing.qualityOfService = .userInteractive
        acceptSharing.perShareCompletionBlock = {meta, share, error in
            print(“successfully shared”)
        }
        acceptSharing.acceptSharesCompletionBlock = {
            error in
            guard (error == nil) else{
                print(“Error \(error?.localizedDescription ?? “”)”)
                return
            }
            
            let viewController: AddItemViewController =
                self.window?.rootViewController as! AddItemViewController
            viewController.fetchShare(cloudKitShareMetadata)
            
        }
        CKContainer(identifier: cloudKitShareMetadata.containerIdentifier).add(acceptSharing)
    }

UserDidAcceptCloudKitShareWith:通知委托您您的应用有权访问共享信息,使您有机会处理新内容。 当您的应用成功共享项目时,它会通过CKAcceptSharesOperation通知您,并在共享过程中通知您问题。

在该方法中,您将创建一个AddItemViewController的新实例,并调用您创建的新函数fetchShare以及感兴趣的元数据。 该方法最终将CKAcceptSharesOperation添加到您的容器中。 要显示记录,请打开AddItemViewController.swift文件,并实现fetchShare方法:

func fetchShare(_ cloudKitShareMetadata: CKShareMetadata){
        let op = CKFetchRecordsOperation(
            recordIDs: [cloudKitShareMetadata.rootRecordID])
        
        op.perRecordCompletionBlock = { record, _, error in
            guard error == nil, record != nil else{
                print(“error \(error?.localizedDescription ?? “”)”)
                return
            }
            DispatchQueue.main.async {
                self.item = record
            }
        }
        op.fetchRecordsCompletionBlock = { _, error in
            guard error != nil else{
                print(“error \(error?.localizedDescription ?? “”)”)
                return
            }
        }
        CKContainer.default().sharedCloudDatabase.add(op)
    }

在此最终方法中,您将获取共享记录并将其分配给全局变量self.item ,然后最后将操作持久保存在用户自己的sharedCloudDatabase数据库上。

结论

在本教程中,您了解了仅需几行代码,即可轻松地与其他用户共享您的私人记录的子集,并让他们在相同的数据上进行协作,这是多么容易。 通过CKShare的强大功能和简单性,您可以选择购物清单项目,邀请用户通过UICloudSharingController表访问您的项目,以及管理用户访问和权限。

除了与用户共享记录外,您还学习了如何在他们的应用程序中接收和显示数据,以及如何将记录存储在他们的共享数据库中。

如您所见,CloudKit在Apple的整个生态系统中都提供了许多便利和强大的功能。 身份验证几乎是不可见的,无需用户使用电子邮件或密码登录,并且同步是实时的。 除了本系列之外,我鼓励您探索更多高级主题,例如将CloudKit与Core Data同步或创建缓存逻辑来管理脱机数据封送。

翻译自: https://code.tutsplus.com/tutorials/building-a-shopping-list-application-with-cloudkit-sharing-shopping-items--cms-31409