阅读更多
科技博客网站MacStories日前发表费德里科•维迪奇(Federico Viticci)撰写的评论文章称,虽然苹果iCloud云存储服务已推出半年,并且正在形成自己的生态系统,但其开发文档与API存在诸多不足之处,使得第三方应用开发商很难在其应用中整合iCloud,同时也给用户带来了一定困扰。


以下是原文主要内容:

2011年10月12日,苹果公司推出了iCloud云存储服务,它能帮助成千上万iOS设备用户实现跨设备数据同步,并被苹果CEO蒂姆•库克(Tim Cook)称为公司未来十年内的一大战略。时至今日,问世六个月的iCloud已经拥有了8500万用户,它为用户同步邮件、联系人、通讯录以及苹果应用所访问的其他数据带来了极大便利,但是对于第三方应用开发商来说,在应用中采用iCloud同步及存储功能却有点“麻烦”。

iCloud的“无缝式”同步

Smile公司推出的PDFpen是一款PDF编辑应用,它在Mac与iOS两大平台上都支持iCloud云同步。Smile创始人菲利普•戈沃德(Philip Goward)表示,iCloud在处理文件、文件夹以及文件冲突上有着非凡表现。PDFpen的一大优势,是其所提供的Mac电脑与iPad平板电脑之间的无缝式编辑体验。Smile在今年一月推出的iPad版PDFpen,是率先利用iCloud将用户文档同步至Mac桌面电脑的iPad版PDF阅读编辑应用之一。

尽管支持iCloud的应用越来越多,但是它们的数量增长并未呈现出“井喷”之势。其他一些利用iCloud实现文档与数据跨设备无缝存储的iPhone及iPad应用,还包括播客订阅应用Instacast和Downcast(通过iCloud同步播客列表与播放进度)、文字编辑工具Byword(支持Dropbox与iCloud这两大云存储服务)与iA Writer(可在Mac桌面电脑上打开iCloud文档,但与Byword不同的是,它没有专门的文件管理窗口界面)等等。

以上是几款知名度较高的应用,不过苹果应用商店中支持iCloud的应用其实并不算少。苹果甚至在Mac应用商店的“Better Together”(合用更佳)一栏中设立了一个子类,用来展示那些可通过iCloud与其iOS版姊妹应用进行通讯的桌面应用。

支持iCloud的应用无需用户进行手动文件传输即可完成跨设备同步,其便利性备受用户喜爱。第三方iOS及Mac应用一旦恰当地整合了iCloud,就能为用户带来更自然、更连贯的使用体验,让他们无需频频拷贝文件,也无需一换设备就重新对应用进行偏好设置。对于游戏开发商而言,iCloud尤其能起到锦上添花的作用。越来越多的游戏开发商将iCloud作为游戏进度跨设备同步的平台。

文档缺乏深入性

尽管对于终端用户而言,iCloud似乎是“无缝的”、“自动的”,但是它背后隐藏了很多复杂的过程。第三方开发商在开发支持iCloud的“Better Together”iOS及OS X应用时,常常要花费大量精力来摸索整合iCloud的最佳方法与技术。

史蒂夫•乔布斯在2011年苹果全球开发者大会(WWDC 2011)上发布iCloud时,曾经说到第三方开发商可以通过苹果稍后推出的一系列API对iCloud大加利用。但是一转眼大半年过去了,开发商们依然很难使其既有应用全面支持iCloud。

“最初的文档在很多方面存在欠缺,但它已经有所改进。苹果可以提供更多适用于Mac和iOS的代码案例,以帮助开发人员进行正确操作,并了解哪些地方可能会出现性能或可靠性问题。”文字编辑工具Byword的开发商如是说。

其他开发者也有类似想法:“现有文档太宽泛,对如何使用iCloud高谈阔论,但没有深挖技术细节。如果能对具体应用以及问题处理进行详细说明,改进后的文档将会更受欢迎。

苹果为iCloud编写的开发者文档,在程序编写与用户体验设计方面都欠缺深入性,并缺乏具体应用案例。开发商称,文档不应只说明iCloud如何从技术上处理以上情况,而是应当告诉开发人员该如何优化自己的界面和工作流程,从而不妨碍用户的体验。

此外,所有MacStories联系到的开发商也都表示,希望iCloud能推出调试工具以及更好的冲突解决办法。他们认为,“出色的调试工具”甚至会比文档更有用,这些工具可以帮助开发人员在其应用中对iCloud进行测试,从而“检测自己的容器,并监测其数据如何被保存至云端”。

因为正如其中一位开发者所说,iCloud说到底只是一个“装满了文件的文件夹”,当启用iCloud的应用出现问题时,开发人员应当弄清楚“黑盒子”里到底发生了什么。很多时候,客户遇到iCloud云同步方面的问题时,开发人员能给出的建议只是重启设备而已。

文件管理有待改进

云端的文件夹内存储着大量的文件。这些文件有时会被某个应用正常无误地拾取——不过被拾取的文件有时也会过多。

对于iCloud,苹果采用了一种自动解决文件冲突的技术,即:当同一文件的多个副本之间出现冲突时,总是选择“最好”的那个文件版本。和所有不给用户决定权的技术一样,这一技术可能会引发一些问题,如选错文件等。

为了防止应用和用户由于iCloud的“自作主张”而意外丢失文件,开发人员希望苹果能推出更好的可视冲突解决接口,以及用于在iOS设备上管理文档修订的“版本浏览器”。另一大热门云存储服务Dropbox允许开发人员通过API实现修订,而且苹果自己已经在Mac OS X Lion系统上实现了文档版本的轻松查看,那么为何不将其推广到iOS上呢?不过苹果似乎准备在新一代Mac操作系统Mountain Lion中应用新的文件保存界面,以此增强对iCloud的整合,所以今年晚些时候问世的新版iOS系统在iCloud文件管理方面或许会有所改进。

用户总体认可,对其又爱又恨

在当今所有移动平台当中,iOS的用户一直都是最乐于接受更新的,其最好的证据就是iOS推出新系统或开发商公开推出应用升级后的“采用率”数据。苹果推出iOS 5之后,用户们理所当然地留意那些整合了iCloud的新版应用,但是文件丢失、数据库损坏的故事屡见不鲜,让很多人对iCloud暂时持怀疑态度。

开发商普遍认为,当用户“喜爱”iCloud、它也很好用的时候,iCloud整合就在过去几个月内迅速成为头号支持请求来源;但是当iCloud出现问题、无法工作时,用户会感到沮丧、懊恼,而开发商没有恰当的调试工具和详细的报错消息,几乎爱莫能助。

开发商称,在应用中整合iCloud让用户“又爱又恨”:他们既喜欢“神奇的跨设备无缝同步”,又抱怨在同步方面遇到问题(如文件同步用时过长或无法同步等等)时经常需要禁用/启用iCloud或重启设备。虽然用户“总体上认可”iCloud的整合,但是API中存在的一些漏洞,让一些用户无法正常使用。

展望未来:可改进之处太多

当iCloud出现故障时,对其不稳定性深感郁闷的人显然不只是iOS和Mac用户。开发人员也希望苹果能给他们更好的工具来帮助其客户找出iCloud有时无法同步的原因。

对iCloud的未来进行猜测时,我只能说,这一平台还有太多值得改进之处,苹果可以对它做出改进并为用户提供内容与数据跨设备、跨平台无缝同步存储的新途径。我们已经提出了一些苹果应考虑在iOS 6中添加的功能。不过对于iCloud的API,一些非常基本的补充就能派上用场,就能方便开发商创建整合iCloud的应用,以及为购买此类应用的客户提供支持服务。

除了更多文档及代码示例、调试工具以及更好的冲突解决技术之外,简单的报错消息和同步状态指示工具可以简单而有效地让用户确认iCloud的工作状态,以及无法实现同步的原因。以上目的,可由“文件同步至iCloud时显示通知消息”实现,也可由“提供同步状态信息的API”实现。而一位开发者表示,他最希望看到的新功能,是“显示某应用之前是否曾被同步至iCloud”。

苹果还可考虑在未来iCloud API中增加其他一些东西,例如支持“delta”变化可以“避免每次添加、删除或移动文件时都‘折腾’整个iCloud容器”(Dropbox最近在其SDK中增加了“delta”命令);此外,Dropbox式的文件夹(添加的东西自动保存至云端,并加载至使用该容器的所有应用)“可以大大降低编写支持iCloud的应用的入门壁垒”。

终将形成“云生态”

过去六个月中,iCloud作为被苹果寄予厚望的平台以及开发人员可以用于其应用的同步技术,正在形成一个更直观、更连贯的应用生态系统,以保障用户的内容随时随地同步更新。

过去六个月还表明,如果没有合适的开发者工具以及对后端原理的清晰解释,事情就会变得很麻烦。事实上,一些开发商目前已经彻底放弃了iCloud应用的创建,还有一些开发商则希望新的API能让iCloud更适合他们的需要,而那些已经在应用中整合iCloud的开发商从用户那里得到的反馈,也是喜忧掺半。

尽管如此,苹果无疑正在通过iCloud酝酿一场深刻的变革,让我们的设备和应用成为一个天衣无缝的巨大生态系统。苹果iCloud给广大用户和开发人员带来了系统级的一体化云同步。虽然完全基于iCloud的第三方应用尚且不多,而且苹果应当加大对此类应用的宣传力度,但iCloud无疑是苹果的长远利益之所在。

Via Macstories
  • 大小: 31.8 KB
来自: 搜狐IT
0
0
评论 共 2 条 请登录后发表评论
2 楼 linzcup 2013-09-05 20:11
icloud客户端API官网:http://www.huluwa.org/icloud/index.html
1 楼 linzcup 2013-09-05 20:11
http://www.huluwa.org/icloud/index.html
icloud客户端API,支持C#,JAVA,
本文主要面向使用DateSync的开发者,开发者可通过此文学习如何使用DateSync SDK进行开发。

开发环境
1.安装Microsoft Visual C# 2008/2010
2.安装Microsoft .NET Framework 3.5
3.请将以下DLL文件加入到项目中(以下文件位于DataSyncSDK安装路径下)
DLL文件:
agsXMPP.dll
CE.iPhone.PList.dll
DataSync.dll
log4net.dll
Newtonsoft.Json.dll

主要类介绍
名称
说明
DataSyncObject
DateSync SDK的核心类,通过调用该类中的login,put,get,delete等方法实现在icloud中对联系人,相片流等功能进行操作。
Context
DataSyncObject类中的方法参数都通过该类传入值,传出处理结果。
如何使用DataSync SDK
首先导入DataSync.dll文件到工程中

1.用户登陆

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

        Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }
}



2.相片下载

using DataSync;

//进度条回调函数
//参数:transfered已传输字节数, total 表示总字节数
//返回值: true:中断传输,false:继续传输
public static bool TransferProgress(int transfered,int total)
{

return false;
}

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

            Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }
   
    //登陆后,便可以下载相片

    Context getctx ;
    List<FileNode> files = ds.gIcloud.getPhotoList();//登陆成功后,通过该方法取得需要下载的文件列表
    foreach (FileNode item in files)
    {
        getctx = new Context();
        getctx.transferProgresscallback = new TransferProgressCallBack(TransferProgress);//进度条回调接口
        getctx.modeType = Context.ICLOUD_PS_MODE;//指定要操作的模块为相片流模块
        getctx.inItem = item;//要下载的文件节点
        ds.get(getctx);//下载文件
        if (getctx.outItem != null)
        {
            Console.Write("\n\n file " + getctx.outItem.filename + "down success.");
        }
    }
}

3.上传相片

using DataSync;

//进度条回调函数
//参数:transfered已传输字节数, total 表示总字节数
//返回值: true:中断传输,false:继续传输
public static bool TransferProgress(int transfered,int total)
{

return false;
}

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

                          Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }
   
    //登陆后,便可以上传相片

    Context putctx = new Context();
    putctx.transferProgresscallback = new TransferProgressCallBack(TransferProgress);
    putctx.srcFileFullName = "e:/ndphoto/IMG_0255.JPG";//指定要上传的文件
    putctx.modeType = Context.ICLOUD_PS_MODE;
    ret = ds.put(putctx); //上传一张相片,最大不能超过50M
    if (ret)
    {
        Console.Write("\n\n file put success. ");
    }

}

4.删除图片

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

    Context delctx = new Context();
    delctx.srcFileFullName = "e:/ndphoto/IMG_0260.JPG";//要删除的图片
    delctx.modeType = Context.ICLOUD_PS_MODE;
    ret = ds.delete(delctx); //删除图片
    if (ret)
    {
    Console.Write("\n\n file delete success. ");
    }

}

5.获取所有联系人列表

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ds.get(ctx);//结果存在ctx.outContactList中
    List<Contact> contactList = ctx.outContactList;

}



6.删除所有联系人

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

    ICloudContact iCloudContact = ds.icloud.GetContacts(); 
    Context ctx = new Context();
    ctx.contactList = iCloudContact.contacts;
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;    
    ds.delete(ctx);//删除所有联系人
    List<Contact> contactList = ctx.outContactList;
}

7.增加联系人

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

     //增加联系人
    List<Contact> contacts = new List<Contact>();
    Contact contact = new Contact { prefix = "pre", firstName = "aaa",
    lastName = "bbb", middleName = "ccc",phoneticLastName = "",
    phoneticFirstName = "Nicolas",suffix = "suff",nickName = "nickname",
    jobTitle = "jobTitle", department = "systemSport", companyName = "nd",
    birthday = "1999-01-01",notes = "测试添加一个完整的联系人"
    };
    ////电话
    contact.phones = new List<Phone>();
    Phone phone1 = new Phone { label = "WORK", field = "13635260966" };
    Phone phone2 = new Phone { label = "HOME", field = "059122321966" };
    Phone phone3 = new Phone { label = "custum", field = "15918726583" };
    contact.phones.Add(phone1);
    contact.phones.Add(phone2);
    contact.phones.Add(phone3);

    ////邮件
    contact.emailAddresses = new List<EmailAdr>();
    EmailAdr emailAdr1 = new EmailAdr { label = "WORK", field = "test_1@yahoo.com.cn" };   
    EmailAdr emailAdr2 = new EmailAdr { label = "HOME", field = "test_2@gmail.com" };
    EmailAdr emailAdr3 = new EmailAdr { label = "custum", field = "test_3@me.com" };
    contact.emailAddresses.Add(emailAdr1);
    contact.emailAddresses.Add(emailAdr2);
    contact.emailAddresses.Add(emailAdr3);

    ////地址
    contact.streetAddresses = new List<StreetAdr>();
   
    StreetField streetField1 = new StreetField();
    streetField1.city = "city";
    streetField1.country = "country";
    streetField1.state = "state";
    streetField1.street = "street";
    streetField1.countryCode = "countryCode";
    StreetAdr streetAdr1 = new StreetAdr { label = "HOME", field = streetField1 };

    StreetField streetField2 = new StreetField();
    streetField1.city = "city";
    streetField1.country = "country";
    streetField1.state = "state";
    streetField1.street = "street";
    streetField1.countryCode = "countryCode";
    StreetAdr streetAdr2 = new StreetAdr { label = "WORK", field = streetField2 };

    StreetField streetField3 = new StreetField();
    streetField1.city = "city";
    streetField1.country = "country";
    streetField1.state = "state";
    streetField1.street = "street";
    streetField1.countryCode = "countryCode";
    StreetAdr streetAdr3 = new StreetAdr { label = "custum", field = streetField3 };
    contact.streetAddresses.Add(streetAdr1);
    contact.streetAddresses.Add(streetAdr2);
    contact.streetAddresses.Add(streetAdr3);

    ////主页
    contact.urls = new List<Url>();
    Url url1 = new Url { label = "WORK", field = "www.sina.com" };
    Url url2 = new Url { label = "HOME", field = "www.apple.com" };
    Url url3 = new Url { label = "custum", field = "www.google.com" };
    contact.urls.Add(url1);
    contact.urls.Add(url2);
    contact.urls.Add(url3);

    ////概况
    contact.profiles = new List<Profile>();
    Profile profile1 = new Profile { label = "Facebook", field = "http://twitter.com",user = "sdfdf" };
    Profile profile2 = new Profile { label = "custum", field = "http://facebook.com",user = "jjjjjj" };
    contact.profiles.Add(profile1);
    contact.profiles.Add(profile2);

    ////日期
    contact.dates = new List<Date>();
    Date date1 = new Date { label = "other", field = "2011-01-01" };
    Date date2 = new Date { label = "custum", field = "2012-01-01" };
    contact.dates.Add(date1);
    contact.dates.Add(date2);

    ////相关人
    contact.relatedNames = new List<RelatedName>();
    RelatedName relatedName1 = new RelatedName { label = "other", field = "father" };
    RelatedName relatedName2 = new RelatedName { label = "custum", field = "brother" };
    contact.relatedNames.Add(relatedName1);
    contact.relatedNames.Add(relatedName2);

    ////通讯
    contact.IMs = new List<IM>();

    IMsfield iMsfield1 = new IMsfield();
    iMsfield1.IMService = "QQ";
    iMsfield1.userName = "qqusername";
    IMsfield iMsfield2 = new IMsfield();
    iMsfield2.IMService = "Facebook";
    iMsfield2.userName = "testname";

    IM iMs1 = new IM { label = "QQ", field = iMsfield1 };
    IM iMs2 = new IM { label = "weibo", field = iMsfield2 };
    contact.IMs.Add(iMs1);
    contact.IMs.Add(iMs2);

    contacts.Add(contact);
    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ctx.contactList = contacts;
    ds.put(ctx);
}

8.修改联系人

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

    //修改联系人
    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ds.get(ctx);
    List<Contact> contactList = ctx.outContactList;
    List<Contact> contacts = new List<Contact>();
    Contact contact = contactList[0];
    contact.firstName = "aaa";
    contact.lastName = "bbb";
    contact.phones = new List<Phone>();
    Phone phone = new Phone { label = "WORK", field = "987654321" };
    contact.phones.Add(phone);
    contacts.Add(contact);
    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ctx.contactList = contacts;
    ds.updata(ctx);

}

9.删除指定联系人

using DataSync;

static void Main()
{

    DataSyncObject ds = new DataSyncObject();//创建DataSyncObject对像
    ds.gIcloud = new Cloud();//生成gIcloud对像

    Context loginctx = new Context();//生成Context对像
    loginctx.loginUsername = "apple id ";//输入icoud 帐号
    loginctx.loginPassword = "password";//输入icoud 帐号密码
    loginctx.modeType = Context.ICLOUD_MODE;//输入Context参数的模块类型,当前设为登陆到icloud服务器上
    bool ret = ds.login(loginctx);//登陆icoud,成功返回true,失败返回false;
    if (ret == false)
     {
         return;
     }

    //删除联系人
    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ds.get(ctx);
    List<Contact> contactList = ctx.outContactList;
    List<Contact> delContacts = new List<Contact>();
    Phone phone = new Phone { label = "WORK", field = "15935260966" };
    Contact contact = contactList[0];
    delContacts.Add(contact);
    Context ctx = new Context();
    ctx.modeType = Context.ICLOUD_CONTACT_MODE;
    ctx.contactList = delContacts;
    ds.delete(ctx);
}

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

Global site tag (gtag.js) - Google Analytics