首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 Watson 和 IoT Platform 服务构建家庭助理移动应用程序(6)

使用 Watson 和 IoT Platform 服务构建家庭助理移动应用程序(6)

开发移动应用程序
因为此应用程序类似于一个聊天消息接口,所以我使用了流行的 iOS 用户界面小部件 JSQMessagesViewController。我可以使用一段类似的,但它是用 Objective C 编写的。不过它仍可提供有用的参考。
开发用户界面准备 Xcode 项目
  • 从 Xcode,单击 File > Project 创建一个单视图应用程序。 选择 Single View            Application 并指定产品名称:Home Assistant。
  • 转到项目文件夹并初始化 CocoaPods。生成了一个          Podfile。
    1
    pod init




  • 将这行代码添加到该 Podfile 来安装 JSQMessagesViewController            小部件。
    1
    pod 'JSQMessagesViewController'




  • 运行下面的命令来安装 JSQMessagesViewController 依赖项。生成了一个 Xcode 工作区。应该使用 Workspace (*.wcworkspace)          而不是 Project (*.xcodeproj) 来重新打开          Xcode。
    1
    pod install




  • 在 ViewController.swift 文件中,导入 JSQMessagesViewController 模块并将            ViewController 类更改为继承自 JSQMessagesViewController            类。声明消息数组来保存聊天消息。
    1
    2
    3
    4
    import JSQMessagesViewController
    class ViewController: JSQMessagesViewController {
      var messages = [JSQMessage]()
    }




  • 最后,在 Info.plist            中输入以下代码来启用麦克风。
    1
    2
    <key>NSMicrophoneUsageDescription</key>
      <string>Need microphone to talk to Watson</string><




设置用户界面并创建一个扩展要设置用户界面并创建一个扩展,请执行以下操作:
  • 创建一个名为 UIExt.swift 的文件,以包含所有 UI 相关逻辑作为 Swift 扩展。然后声明一个扩展。
    1
    2
    extension ViewController {
    }




  • 创建一个 SetupUI() 函数用于:
    • 初始化 title、senderId 和 senderDisplayName。
    • 创建一个麦克风按钮并向 callback 函数注册 touchDown 和                touchUpInside 事件。
    • 注册一个菜单项(合成为 callback 函数)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    func setupUI() {
        self.title = "Watson Chat"
        self.senderId = UIDevice.current.identifierForVendor?.uuidString
        self.senderDisplayName = UIDevice.current.identifierForVendor?.uuidString
         
        JSQMessagesCollectionViewCell.registerMenuAction(#selector(synthesize(sender))
         
        // Create mic button
        let microphoneImage = UIImage(named:"microphone")!
        let microphoneButton = UIButton(type: .custom)
        microphoneButton.setImage(microphoneImage, for: .normal)
        microphoneButton.imageView?.contentMode = UIViewContentMode.scaleAspectFit
        self.inputToolbar.contentView.leftBarButtonItem = microphoneButton
         
        // Add press and release mic button
        microphoneButton.addTarget(self, action:#selector(didPressMicrophoneButton), for: .touchDown)
        microphoneButton.addTarget(self, action:#selector(didReleaseMicrophoneButton), for: .touchUpInside)
         
        setAudioPortToSpeaker()
      }




  • 添加麦克风图标作为资产。单击 Assets.xcassets,将图标文件拖到工作区来创建图像集。
点击查看大图

实现用户界面的处理函数在 UIExt.swift 文件中:
  • 添加以下函数来处理麦克风按钮按下事件。按下此按钮来说出命令时,它就会开始将信息传输到 Watson Speech to Text            服务。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    func didPressMicrophoneButton(sender: UIButton) {
        let microphonePressedImage = UIImage(named:"microphone_pressed")!
        sender.setImage(microphonePressedImage, for: .normal)
        AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
        // Clear the input text
        self.inputToolbar.contentView.textView.text = ""
        // speech-to-text startStreaming
        sttStartStreaming()
      }




  • 添加以下函数来处理麦克风按钮释放事件,这会停止向 Watson Speech to Text            服务传输数据。
    1
    2
    3
    4
    5
    6
    func didReleaseMicrophoneButton(sender: UIButton){
        let microphoneImage = UIImage(named:"microphone")!
        sender.setImage(microphoneImage, for: .normal)
        // speech-to-text stop streaming
        self.sttStopStreaming()
      }




  • 重写 didPressSend() 函数来处理发送按钮按下事件。该代码将消息附加到消息数组,然后向 Watson Conversation            服务发送一条请求并接收一条响应。
    1
    2
    3
    4
    5
    6
    7
    8
    override func didPressSend(
    _ button: UIButton!,
    withMessageText text: String!,
    senderId: String!,
    senderDisplayName: String!,
    date: Date!) {
        send(text)
      }




重写 UI        回调函数在 UIExt.swift 文件中,添加以下函数:
  • 重写 collectionView | numberOfItemsInSection            回调函数,以便返回数组中的消息数量。
    1
    2
    3
    4
    override func collectionView(_ collectionView: UICollectionView,
        numberOfItemsInSection section: Int) -> Int {
        return self.messages.count
      }




  • 重写 collectionView | cellForItemAt            回调函数,该函数负责设置索引路径上的特定单元的文本并呈现它的颜色。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
      override func collectionView(_ collectionView: UICollectionView,
        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
        let message = self.messages[indexPath.item]
        if !message.isMediaMessage {
          if message.senderId == self.senderId {
            cell.textView.textColor = UIColor(R: 0x72, G: 0x9B, B: 0x79)
          } else {
            cell.textView.textColor = UIColor(R: 0x47, G: 0x5B, B: 0x63)
          }
          let attributes : [String:AnyObject] =
              [NSForegroundColorAttributeName:cell.textView.textColor!, NSUnderlineStyleAttributeName: 1 as AnyObject]
          cell.textView.linkTextAttributes = attributes
        }
        return cell
      }




  • 重写 collectionView | messageBubbleImageDataForItemAt            回调函数,以返回响应来表明它是索引路径上的特定单元的传入还是传出气泡。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    override func collectionView(_ collectionView: JSQMessagesCollectionView!,
        messageBubbleImageDataForItemAt indexPath: IndexPath!) -> JSQMessageBubbleImageDataSource! {
        let data = messages[indexPath.row]
        switch(data.senderId) {
        case self.senderId:
          return self.outgoingBubble
        default:
          return self.incomingBubble
        }
      }




  • 重写 collectionView | attributedTextForMessageBubbleTopLabelAt            回调函数,以便设置并返回发送者名称作为消息气泡上的标签(在样式属性旁边):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    override func collectionView(_ collectionView: JSQMessagesCollectionView!,
        attributedTextForMessageBubbleTopLabelAt indexPath: IndexPath!) -> NSAttributedString! {
        if let message = firstMessage(at: indexPath) {
          let paragraphStyle = NSMutableParagraphStyle()
          paragraphStyle.alignment = NSTextAlignment.left
          let attrs = [
            NSParagraphStyleAttributeName: paragraphStyle,
            NSBaselineOffsetAttributeName: NSNumber(value: 0),
            NSForegroundColorAttributeName: UIColor(R: 0x1e, G: 0x90, B: 0xff)
          ]
          return NSAttributedString(string: message.senderDisplayName, attributes: attrs)
        } else {
          return nil
        }
      }




  • 重写 collectionView | heightForMessageBubbleTopLabelAt            回调函数,以便返回文本标签的高度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    override func collectionView(_ collectionView: JSQMessagesCollectionView!,
      layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!,
      heightForMessageBubbleTopLabelAt indexPath: IndexPath!) -> CGFloat {
        if let _ = firstMessage(at: indexPath) {
          return kJSQMessagesCollectionViewCellLabelHeightDefault
        } else {
          return 0.0
        }
      }




返回列表