如何在安装时备份sis文件

原帖

 

ID N/ACreation date January 19, 2010
Platform Symbian Tested on devices S60
Category Symbian C++Subcategory S60 5th Edition
Keywords (APIs, classes, methods, functions): TOpenFileScan 

目录

概述


有多款免费或商用S60应用程序 支持“蓝牙 分享”功能, 例如广受欢迎的免费软件Paint Pad 就有一个“分享应用程序”菜单项,当选择该菜单项时它能通过蓝牙向配对设备发送一份安装包。通过观察能发现,该应用程序在安装过程中将安装包备份到了系统盘(C:盘)。本文(附以一个完整的示例程序)展示如何实现这个功能。

方案


总的方案可以用一句话阐明:我们需要开发一个在运行时执行的程序,该程序可以找到包含它的sis文件并将该文件拷贝到指定位置。这句话的前半部分可以通过包文件的高级选项 FR、RI和RW等实现。(注意: 这些选项对于自签名的安装包不起作用),所以我们将注意力放在后半部分上。

在讨论如何查找正在被安装的sis文件之前,让我们先提两个假设,以简化我们的调查过程。

假设一: sis文件在被安装的过程中处于打开状态

该假设可以通过以下测试用例确认,

第1步:使用S60文件管理器打开一个sis文件

第2步:使用另一个文件管理器删除该文件,删除失败并报错“已被使用!”,这表示sis文件处于打开状态(即正在被安装程序使用)

假设二: 同一时间只能安装一个sis文件

该假设可以通过以下测试用例确认,

第1步:使用S60文件管理器打开一个sis文件,并按安装程序的提示操作,直到出现盘符选择对话框

第2步:使用另一个文件管理器打开该文件,操作失败并报错“安装程序已经在运行,无法再次启动”,这说明安装程序是单实例的。

在这两个假设下,刚才的问题可以被简化成:如何查找一个打开的sis文件?(当然可以用sis文件的其它特性进一步确认,例如文件的UID)。一个显而易见的答案是遍历整个文件系统逐一对比查找文件,它可以作为备选方案一,

备选方案一: 通过遍历整个文件系统查找所需要的文件。

这个方案可以用File Server client APIs实现,例如TFindFileCDirScan ,但是在系统盘和大容量存储器上可能有几十个目录和几百个文件,为了避免安装时长时间的等待,最好能减小文件查找的范围。值得庆幸的是,有一个系统APITOpenFileScan能获取所有处于打开状态的文件 - 这正是我们想要的!

备选方案二: 使用TOpenFileScan,通过遍历所有打开的文件查找所需要的文件。

在 使用这个方案时小心两个“陷阱”:一是每次调用TOpenFileScan::NextL()只会创建某个特定的文件服务器会话打开的文件列表,所以必须 循环调用该函数,只到它返回NULL或者找到所需要的文件;二是通过这个API获取的文件名不带盘符,例如是"//data //HelloWorld.sis"而不是"C://data//HelloWorld.sis"。

...

  _LIT(KExtSis, ".sis" );   

  _LIT(KExtSisx, ".sisx" );   

  RFs fs;   

  TInt err = fs.Connect();   

  User::LeaveIfError(err);   

  CleanupClosePushL(fs);       

    TFileName filename;       

    TOpenFileScan ofs(fs);       

    TBool done = EFalse;       

    while(!done)           

      {           

      CFileList* fl = NULL;           

      ofs.NextL(fl);s           

      if (fl==NULL) /** NextL()应该被反复调用,直到它返回NULL */                

        {               

        done = ETrue;               

        }           

      else               

        {               

        CleanupStack::PushL(fl);                   

          TInt count = fl->Count();                   

          for (TInt i= 0; (i<count)&&(!done); i++) /** 对于每一个处于打开状态的文件 */

            {                       

            TEntry entry = (*fl)[i];                       

            TParsePtrC parse(entry.iName);                       

            if((parse.Ext()==KExtSis)||(parse.Ext()==KExtSisx)) /** 查找第一个类型是sis的文件 */

              {                           

              filename = entry.iName;                           

              done = ETrue;                           

              }       

            }        

        CleanupStack::PopAndDestroy(fl);               

        }           

      }       

    if(filename!=KNullDesC)           

      {           

      /** 找到了!注意:文件名不含盘符 */            

      }   

  CleanupStack::PopAndDestroy(&fs);

...

文件名找到了,但在支持Data caging 的系统中程序并不总能在所有目录之间拷贝文件,因此在执行拷贝操作之前让我们看一下文件可能保存在哪些目录中,

目录 说明
信息应用程序的私有目录即文件是通过蓝牙、红外或其它协议发送到手机上的,这种情况下必须使用Messaging APIs 获取文件
其它私有目录不太可能,因此忽略这种情况
/resource目录不太可能,而且任何应用程序都能读取资源文件下的文件
/sys目录不太可能,因此忽略这种情况


了 解了这些情况就能继续编码了。如果文件位于信息应用程序的私有目录,那么必须使用Messaging API获取它。Messaging API的使用不是本文的重点,因此这里不再赘述。本文的示例程序能够提取处理蓝牙信息的附件,如果感兴趣的话可以看一下 CSmsHandler::ExportInboxToFileL()的实现。

如之前提到的,我们获取的文件名没有盘符,因此我们必须使用RFs::DriveList() 列出所有可用的盘符,然后逐一检查文件是否存在,如果存在还要进一步检查该文件是否处于打开状态(即无法被修改)。如果一切顺利的话最终我们能用盘符补全文件名,然后就能将文件拷贝到指定位置(例如本文的示例程序将文件拷贝到c:/sisback目录)

...

_LIT(KSisBackup, "c: //sisbackup //backup.sis" );

_LIT(KMessagingPrivateFolder, " //private //1000484b //" );

_LIT(KPrivateFolder, " //private //" );

_LIT(KSysFolder, " //sys //" );

...       

  if(filename!=KNullDesC)           

    {           

    /** 续上,找到了! */

    BaflUtils::EnsurePathExistsL(fs, KSisBackup); /** 确保目标目录存在 */

    filename.LowerCase(); /** 将所有字符转换成小写以方便比较 */             

    if(filename.Find(KMessagingPrivateFolder)==0)               

      {               

      /** 文件位于信息应用程序的私有目录,无法直接获取,但可以尝试用Messaging API获取 */

      }           

    else if(filename.Find(KPrivateFolder)==0)               

      {               

      /** 文件位于其它私有目录,无法直接获取 */                

      }           

    else if(filename.Find(KSysFolder)==0)               

      {               

      /** 文件位于系统目录,无法直接获取 */                

      }           

    else               

      {               

      /** 文件位于其它目录(包括资源文件),可以直接获取 */                 

      _LIT(KDriveC, "c:" );               

      filename.Insert(0, KDriveC); /** 文件名无盘符,因此添加占位符 */                

      TBool found = EFalse;               

      TDriveList driveList;               

      err = fs.DriveList(driveList);               

      User::LeaveIfError(err);               

      for(TInt driveNumber=EDriveA; (driveNumber<EDriveZ)&&(!found); driveNumber++)

        {                   

        if (driveList[driveNumber]) /** 遍历所有可用盘符 */

          {                       

          TChar driveLetter;                       

          err = fs.DriveToChar(driveNumber,driveLetter);

          User::LeaveIfError(err); 

          filename[0] = driveLetter; 

          TEntry entry;  

          err = fs.Entry(filename, entry);

          if(err==KErrNone) /** 检查文件是否在该盘上 */

            {                           

            err = fs.SetModified(filename, entry.iModified); /** 如果存在则检查它是否打开 */

            if(err!=KErrNone) /** KErrInUse。 或KErrPermissionDenied,如果文件位于资源文件 */

              { 

              found = ETrue;

              } 

            } 

          }

        }

      if(found)

        { 

        /** 终于找到了!将文件拷贝到指定位置 */

        err = BaflUtils::CopyFile(fs, filename, KSisBackup); 

        User::LeaveIfError(err);

        } 

      }

    }

...

看上去“任务”完成了,但在结束讨论之前还必须考虑以下两个问题:

(1) 在卸载时要删除备份文件。这一点可以通过在.pkg文件中添加一行带“FN”标记的指令实现。

...

""  -  "c:/sisbackup/backup.sis", FN

...

(2) 如果安装被中途撤销则不应该有备份文件。本文的示例程序没能正确地处理这一点,希望有人解决这个问题并更新wiki。

示例

完整的示例程序: HelloWorld(SisBackup).zip

该示例程序在S60 5th Edition SDK 上构建通过,在一台S60 5th Edition手机上测试通过。

如何使用:

1. 为目标设备构建/SisBackup程序

2. 为目标设备构建/HelloWorld应用程序,并制做sis文件

3. 用SymbianSigned签名签署该sis文件

4. 将签名后的sis文件拷贝到手机上(或通过蓝牙发送到手机上)

5. 安装签名后的sis文件,然后启动HelloWorld应用程序,然后选择“选项”->“Share”,如果能看到显示“c:/sisbackup/backup.sis”的提示就说明sis文件已经成功地被备份到系统盘上了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值