您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
如何在Swift中创建Action扩展
 
作者 汤泳,火龙果软件    发布于 2014-10-17
   次浏览      
 

我们先想象一下,我们已经有一个很牛逼的应用了,我们姑且叫做重要信息记事本。它的功能就是将我们认为是重要的信息记录下,便于我们随时查看。那么何为重要信息呢?重要信息可以是很多类型的信息,比如武功秘籍、食谱、生日、一段牛逼的代码等等。当我们已经有了这样一个应用后,接下来应该考虑的事情就是如何记录重要信息了。通常思维下,你们可能认为应该是先打开这个应用,然后将重要信息敲进去。是这样么?你当用户是傻子么,什么年代了还手敲,简直弱爆了。下面我向你们介绍一个很酷的方法,那就是通过Action扩展,将信息记录到我们的应用中。下面例子的主要功能是将Safari浏览的网页中的信息保存在我们应用中。

见证奇迹的时刻

先通过 File > New > Project 菜单创建一个新的工程,选择 Single View Application :

然后通过 File > New > Target 菜单给给工程添加一个 Target ,选择 Action Extension :

在创建Action扩展时需要指定一个Aciton类型,Apple提供了两种Action扩展的类型模板。一种是有用户界面的类型,包含一个 UIViewController 和一个 Storeboard 文件,可以自定义显示界面和行为。另一种是不带用户界面的类型,这种类型只允许我们处理来自Host应用的请求。

现在我们在工程中就可以看到刚才创建的Action扩展 NoteAppExtension ,它包含两个主要的文件,一个是 Action.js ,另一个是 ActionRequestHandler.swift :

我们来看看这两个文件的作用。 Action.js 文件用来实现和处理浏览器中请求的逻辑,在本文的例子中,它主要实现用户在浏览器中选中文本并发送到我们的应用中。 ActionRequestHandler.swift 用来处理Host应用发送的请求和参数。

在实现逻辑之前我们需要设置一下扩展的属性,打开 Info.plist 文件将 NSExtensionActivationSupportsWebURLWithMaxCount 属性设置为1,该设置让扩展知道我们需要请求一个URL。

我们 Action.js 文件中有如下内容:

var Action = function() {};
 
Action.prototype = {
    
    run: function(arguments) {
  // 在这个方法里,你可以通过document操作HTML中的元素,
或者可以将HTML中的内容传给ActionRequestHandler文件的代码。
  
  // 在本文的例子中,我们不做任何更新,只是将HTML中选中的内容穿给ActionRequestHandler文件的代码。
  var selected = "No Text Selected";
  if (window.getSelection) {
      selected = window.getSelection().getRangeAt(0).toString();
  } else {
      selected = document.getSelection().getRangeAt(0).toString();
  }
  arguments.completionFunction({"args" : selected});
    },
    
    finalize: function(arguments) {
  // 当ActionRequestHandler文件中的itemLoadCompletedWithPreprocessingResults方法执行完之后会调用该方法。
  
  // 如果ActionRequestHandler文件向HTML返回了信息,
我们可以通过arguments["message"]来查看,并且可以根据该信息操作HTML中的元素。
  alert(arguments["message"])
    }
};
    
var ExtensionPreprocessingJS = new Action

Safari与Action扩展的交互就是通过 Action.js 文件中的 run 和 finalize 这两个方法实现的。当我们在Safari中使用Action扩展时就会调用 run 方法,它能让我们在该方法中操作当前Safari显示页面的DOM元素。当Action扩展处理完逻辑向Safari返回信息时会调用 finalize 方法,在我们的例子中,我们通过 self.extensionContext!.completeRequestReturningItems(nil, completionHandler: nil) 这段代码向Safari返回信息。该方法的第一个参数就是要返回的信息,它会将信息传给 Action.js 文件,然后通过js代码操作HTML。如果第一个参数传入 nil ,那就意味着不会调用 Action.js 文件中的 finalize 方法。 run 和 finalize 这两个方法的参数 arguments 都包含着一些信息,只不过一个是来自与HTML,一个来自 ActionRequestHandler 文件。

一定要记住: 我们必须要实例化 ExtensionPreprocessingJS 这个全局变量,因为它是Safari和Action扩展之间的桥梁。

我们的 ActionRequestHandler 文件内容如下:

class ActionRequestHandler: NSObject, NSExtensionRequestHandling {
 
  var extensionContext: NSExtensionContext?
  
  func beginRequestWithExtensionContext(context: NSExtensionContext!) {
    self.extensionContext = context
    let identifierType = NSString(format: kUTTypePropertyList, NSUTF8StringEncoding)
    for (item: NSExtensionItem) in context.inputItems as [NSExtensionItem] {
      for (itemProvider: NSItemProvider) in item.attachments as [NSItemProvider] {
        if itemProvider.hasItemConformingToTypeIdentifier(identifierType) {
          itemProvider.loadItemForTypeIdentifier(identifierType, options: nil, completionHandler: {(item, error) in
            let dictionary = item as NSDictionary
            dispatch_async(dispatch_get_main_queue(), {
              self.itemLoadCompletedWithPreprocessingResults
(dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as NSDictionary)
            })
          })
        }
      }
    }
  }
  
  func itemLoadCompletedWithPreprocessingResults(javaScriptPreprocessingResults: NSDictionary) {
    if let text = javaScriptPreprocessingResults["args"] as? String {
      let userDefaults = NSUserDefaults(suiteName: "group.name")
      userDefaults.setValue(text, forKey: "note")
      userDefaults.synchronize()
      self.doneWithResults(["message": "Successfully added to the note app"])
    }
  }
  
  func doneWithResults(resultsForJavaScriptFinalizeArg: NSDictionary?) {
    if let resultsForJavaScriptFinalize = resultsForJavaScriptFinalizeArg {
      let identifierType = NSString(format: kUTTypePropertyList, NSUTF8StringEncoding)
      // 创建合适返回类型的标示符。			

      // 这里创建的resultsItem将作为Action.js文件中finalize方法的参数。
      var resultsDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: resultsForJavaScriptFinalize]
      
      var resultsProvider = NSItemProvider(item: resultsDictionary, typeIdentifier: identifierType)
      
      var resultsItem = NSExtensionItem()
      resultsItem.attachments = [resultsProvider]
      
      // 这段代码意味着Action扩展已经处理完了逻辑,现在将信息返回给Action.js文件。
      self.extensionContext!.completeRequestReturningItems([resultsItem], completionHandler: nil)
    } else {
      // 就算我们没有任何要返回的信息,也要执行这段代码,用于告知我们的Action扩展已经完成了逻辑处理。
      self.extensionContext!.completeRequestReturningItems(nil, completionHandler: nil)
    }
    
    self.extensionContext = nil
  }
}

现在我们可以运行一下我们的应用,然后打开Safari,在Action选项中开启我们的Action扩展:

然后我们就可以在Action栏中看到我们的扩展了:

我们使用Safari随便打开一个含有文字的页面,选中一段文字,然后打开Action栏,点击 NoteApp 扩展,此时我们的扩展就会将选中的这段文字发送给我们的应用,形成一条新的重要信息。

以上只是一个简单的Aciton扩展的例子,但我们可以由此延伸出更多有用、有创意的功能,让我们的生活更加美好。

   
次浏览       
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
Node+Vue3.0前端全栈开发 7-5 [特惠]
Spring Cloud微服务架构 7-5[特惠]
SysML和EA系统设计与建模 7-26[特惠]
Python、数据分析与机器学习 8-23[特惠]
嵌入式软件架构设计 8-22[线上]
Linux内核编程及设备驱动 7-25[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...