2014 年 12 月 30 日
教程:使用 CoronaCards 和 Swift 实现“发送至”功能
在之前的教程中,我们向您展示了如何将 CoronaCards 与 Swift 结合使用。在本教程中,我们将在一个基于 CoronaCards 的应用中实现一个原生功能:发送至按钮,其标识如下
在许多 iOS 应用中,当您按下发送至按钮时,会弹出一个“共享面板”,让您可以通过 Twitter、Facebook 和其他服务共享您的信息,并提供打印和 AirDrop 等功能。在原生术语中,此面板被称为 UIActivityViewController。方便的是,这可以使用 CoronaCards 来实现。
在继续之前,请确保您已经安装了之前教程中的 CoronaCards 模板,并且您可以构建其中呈现的项目。
设置
首先,使用 CoronaCards “单视图”模板创建一个新的 Xcode 项目。然后,为您的项目命名并将您的 CoronaCards license.ccdata
文件复制到核心项目文件夹,其中包含 main.lua
。
Corona 端
CoronaCards 模板为您提供了“HelloPhysics”示例应用作为起点,本教程将在此基础上构建。我们的“发送至”Corona 应用将提供一个按钮来调用共享,但首先我们需要一些共享内容。为此,应用将使用 display.captureScreen() 捕获屏幕,并使用 display.save() 将其保存到临时文件。然后,代码将向原生端发送一个事件,在该事件中将显示 UIActivityViewController
,并且此事件将包含文本消息、捕获的图像和 URL。当控制器完成时,它将在 Corona 端触发一个事件,告诉您的应用它是否完成以及选择了什么服务。最后,将使用 display.newText() 对象来显示结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
--------------------------------------------------------------------------------------- -- 一个简单的物理示例,仅需 8 行! --------------------------------------------------------------------------------------- local physics = require( "physics" ) -- -- Hello Physics 示例应用 -- physics.start() local sky = display.newImage( "sky.png", 160, 195 ) local ground = display.newImage( "ground.png", 160, 445 ) local crate = display.newImage( "crate.png", 180, -50 ) crate.rotation = 5 physics.addBody( ground, "static", { friction=0.5, bounce=0.3 } ) physics.addBody( crate, { density=3.0, friction=0.5, bounce=0.3 } ) -- -- 设置共享“按钮”和结果文本对象 -- local shareText -- 前向声明按钮 local resultText = display.newText( "", display.contentCenterX, 20, "HelveticaNeue", 20 ) -- -- 设置与 Swift 的通信 -- local function handleTap( event ) -- -- 捕获屏幕 -- 此外,最初隐藏按钮 -- shareText.isVisible = false local screen = display.captureScreen( false ) -- -- 将捕获内容保存到临时目录 -- display.save( screen, { filename="screencapture.jpg", baseDir=system.TemporaryDirectory, isFullResolution=true, backgroundColor={0,0,0,0} } ) screen:removeSelf() screen = nil -- -- 显示按钮 -- shareText.isVisible = true local event = { name = "coronaView", message = "我刚刚看了Hello Physics!", image = { filename="screencapture.jpg", baseDir=system.TemporaryDirectory }, url = "" } -- 将数据分发到全局 Runtime 对象 Runtime:dispatchEvent( event ) return true end shareText = display.newText( "分享", display.contentCenterX, 200, "HelveticaNeue", 24 ) shareText:addEventListener( "tap", handleTap ) shareText.x = display.contentCenterX shareText.y = display.contentHeight - 15 -- -- 设置一个监听器来处理来自 Swift 的返回事件 -- local function sendToComplete( event ) print( "sendToComplete" ) print( event.name ) -- "sendTo" 的字符串值 print( event.complete ) -- true 或 false 的布尔值 print( event.activity ) -- 活动名称 if ( event.complete ) then resultText.text = "通过 " .. event.activity 分享" else resultText.text = "已取消" end return true end Runtime:addEventListener( "sendTo", sendToComplete ) |
让我们检查一下这段代码的关键部分。按下分享“按钮”(shareText
)会触发对象的处理函数 handleTap()
,在该函数中会捕获屏幕。然后将捕获的屏幕保存到 system.TemporaryDirectory
文件夹中。接下来,构建一个事件表。原生端监听一个名为 coronaView
的事件,它需要一些文本、一个 URL 和一个图像,因此我们将这些项目添加到事件表中。最后,我们将事件分发到全局 Runtime。
当 UIActivityViewController
完成时(见下文),它会将一个事件发送回 CoronaCards 端。 这需要一个 Runtime 事件监听器,我们将其称为 sendTo
,它将通信信息是否已共享或是否已取消。 如果已共享,它将返回使用的方法。
Swift 端
在 Swift 端,我们需要对 ViewController.swift
文件进行一些更改。 为了参考,整个文件如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
// // ViewController.swift // ActivityController // // 创建者 Rob Miracle 于 2014/12/28. // 版权所有 (c) 2014 Corona Labs. 保留所有权利. // import UIKit class ViewController : CoronaViewController, CoronaViewDelegate { var coronaView: CoronaView! = nil override func viewDidLoad() { super.viewDidLoad() // 在 加载视图后执行任何其他设置,通常来自 a nib. coronaView = self.view as CoronaView // 强制向下转型 coronaView.coronaViewDelegate = self coronaView.run() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // 释放可以重新创建的任何资源. } func coronaView(view: CoronaView, receiveEvent event: NSDictionary) -> AnyObject? { /* event 字典包含: message = 要分享的文本 image = 包含文件名和路径的NSDictionary url = 要发布的URL */ let message: String = event["message"] as String let imageData = event["image"] as NSData let image:UIImage = UIImage(data: imageData as NSData)! let myURL:String = event["url"] as String let url = NSURL(string: myURL) shareTextImageAndURL(sharingText: message, sharingImage: image, sharingURL: url) return(true) } func shareTextImageAndURL(#sharingText: String?, sharingImage: UIImage?, sharingURL: NSURL?) { var sharingItems = [AnyObject]() var view = self.view as CoronaView if let text = sharingText { sharingItems.append(text) } if let image = sharingImage { sharingItems.append(image) } if let url = sharingURL { sharingItems.append(url) } let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil) activityViewController.completionHandler = {(activityType, completed:Bool) in if !completed { println("已取消") let event = ["name":"sendTo", "complete":false] view.sendEvent(event) return } else { println("完成 \(activityType)") let event = ["name":"sendTo", "complete":true, "activity":activityType] view.sendEvent(event) } } self.presentViewController(activityViewController, animated: true, completion: nil) } } |
第一个更改是设置一个委托来处理事件 - 这是其他控制器如何在 CoronaCards 端“与”您的 CoronaView 通信的方式。我们还将 CoronaViewDelegate
添加到类声明的末尾。
从 CoronaCards 接收事件的事件处理程序需要被调用 coronaView
。因此,我们必须将 view
重命名为 coronaView
并将其声明为 ViewController
类的一部分。此外,我们将在运行 CoronaView 之前连接委托。
接下来,我们需要设置事件处理函数,该函数将接收来自 Corona 的数据。在函数内部,我们从事件表中提取各种字段。有趣的是,图像条目不包含文件名和路径,而是包含二进制图像数据,并且以 NSData
类型到达,我们可以将其转换为 UIImage
类型。此外,我们将 URL 从字符串转换为 NSURL
。
准备好数据后,我们调用函数 shareTextImageAndURL
,将对象传递给该函数。shareTextImageAndURL
函数只是查找三个对象中的每一个,并将它们添加到 sharingItems
数组中。
最后,我们创建 UIActivityViewController
,用我们要共享的项目初始化它,并指示它使用所有可用选项。对于 UIActivityViewController
的完成处理程序,如果控制器被取消,我们设置一个名为 sendTo
的事件表(如 CoronaCards 侧所定义),并将 complete
条目设置为 false
。在 else
子句中,我们设置一个 complete
设置为 true
的事件表,并将 activity
设置为 activityType
。在这两种情况下,我们都会将事件发送到 CoronaCards 视图。最后,我们指示控制器通过 presentViewController()
命令显示。
结论
正如本教程所演示的,CoronaCards 使您可以访问各种原生功能,从而扩展基于 Corona 的项目的能力。和往常一样,请在下方贡献您的问题和意见。
埃里希·格吕特纳·D.
发布于 17:45,12 月 30 日谢谢,来得正是时候!!!
新年快乐,CoronaLabs 团队!!!
JCH_APPLE
发布于 08:22,1 月 2 日如果能有一个使用 Corona Enterprise 的相同示例,来展示两种方式之间的差异会很好:使用 Corona 的原生方式和使用原生的 Corona 方式。
罗伯,感谢您提供的所有精彩教程,并祝 Corona 的人们新年快乐。
罗伯·米拉科
发布于 14:58,1 月 2 日使用 ObjC 的方法并没有太大的不同。我对 Enterprise 的理解不是很深入,但如果是我,我会回到我做的 Enterprise 教程,并把它变成一个插件。也许可以把它命名为 plugin.sendto。该教程也有原生和 Corona 之间的数据传递。
唯一的问题是,它需要使用 UIActivityViewController 的 ObjC 版本,而不是 Swift 版本。对于 CoronaCards,Lua 库(和 lua_State 结构)位于 Objective C 类后面,Swift 可以轻松桥接。然而,在 Enterprise 示例中,当前的插件代码是 C++ 与 C 库通信,ObjC 调用 C++。Swift 和 C/C++ 之间的桥接需要做更多的工作才能实现,我目前还没到那一步。
JCH_APPLE
发布于 04:01,1 月 3 日谢谢。我会尝试,如果成功,我会发布结果。打印在商业应用中非常有用。
corona273
发布于 22:30,1 月 6 日请注意,还有一个未解决的功能请求,要求将 iOS 共享表添加到 Corona SDK(这是一个简单的添加,并且已经支持 Android 共享面板)
http://forums.coronalabs.com/topic/53371-supporting-ios-modal-share-action-sheet-airdrop-print-add-to-home-screen-add-bookmark-add-to-reading-list-etc/
罗伯,对此有何想法,何时可能会实现?
穆斯塔法
发布于 00:47,1 月 7 日谢谢你,罗伯,
Pro 版本可以实现吗?
罗伯·米拉科
发布于 16:04,1 月 7 日不,Pro 版本不可用。我们需要人们投票支持它。请访问 http://feedback.coronalabs.com,查找现有功能请求或创建新请求。
罗伯