通过Voice Memos App中的“open in:”导出音频文件

时间:2016-04-21 08:01:14

标签: ios xcode

我和#34;保罗"完全相同。发布在此处:Can not export audiofiles via "open in:" from Voice Memos App - 尚未在此主题上发布任何答案。

基本上我想做的事情很简单: 在iOS上录制语音备忘录后,我选择"打开"从显示的弹出窗口我希望能够选择我的应用程序。

我已经尝试了所有我能想到的并尝试使用LSItemContentTypes而没有成功。

不幸的是,我没有足够的声誉对上面的现有帖子发表评论,而且我非常渴望找到解决方案。任何帮助都非常感激,甚至只是为了知道它是否可行。

谢谢!

1 个答案:

答案 0 :(得分:4)

经过一些实验和此博客文章(http://www.theappguruz.com/blog/share-extension-in-ios-8)的大量指导后,似乎可以使用应用扩展程序(特别是动作扩展程序)和应用程序组的组合来完成此操作。我将介绍第一部分,它将使您能够将语音备忘录录制到您的应用扩展程序。第二部分 - 从应用扩展程序录制到包含应用程序(您的"主要"应用程序) - 可以使用应用程序组完成;请参阅上面的博文,了解如何执行此操作。

  1. 通过选择文件>在项目中为应用扩展程序创建新目标。新>目标...来自Xcode的菜单。在提示您选择"为新目标选择模板的对话框中:"选择"动作扩展"然后单击"下一步"。
  2. 注意:请勿选择" Share Extension"正如在上面的博客文章示例中所做的那样。这种方法更适合与其他用户共享或发布到网站。

    1. 填写"产品名称:"对于您的Action Extension,例如MyActionExtension。此外,对于"行动类型:"我选择了#34;呈现用户界面"因为这是Dropbox出现的方式。选择此选项会将视图控制器(ActionViewController)和情节提要(Maininterface.storyboard)添加到您的应用扩展程序。视图控制器是向用户提供反馈并为用户提供重命名音频文件的机会的好地方,然后再将其导出到您的应用程序。

    2. 点击"完成。"系统将提示您"激活“MyActionExtension”方案?"。点击"激活"这个新计划将变得活跃。构建它将构建动作扩展和包含应用程序。

    3. 点击" MyActionExtension"的显示三角形。 Project Navigator(Cmd-0)中的文件夹,用于显示新创建的故事板,ActionViewController源文件和Info.plist。您需要根据需要自定义这些文件。但是现在......

    4. 构建并运行刚刚创建的方案。系统将提示您"选择要运行的应用程序:"。选择"语音备忘录"从列表中单击"运行"。 (您可能需要一个物理设备;我不认为模拟器上有语音备忘录。)这将构建并将您的动作扩展(及其包含应用程序)部署到您的设备。然后继续发布#34; Voice Memos"在你的设备上。如果您现在使用"语音备忘录"进行录音。然后尝试共享它,您应该在底行看到您的动作扩展名(带有空白图标)。如果你在那里看不到它,请点击"更多"该行中的按钮,并将您的操作扩展名的开关设置为" On"。点击您的操作扩展程序只会显示一个空白视图,其中包含"完成"按钮。模板代码查找图像文件,找不到任何内容。我们将在下一步中解决此问题。

    5. 修改ActionViewController.swift进行以下更改:

    6. 6a上。在文件顶部附近添加AVFoundation和AVKit的import语句:

      // the next two imports are only necessary because (for our sample code)
      // we have chosen to present and play the audio in our app extension.
      // if all we are going to be doing is handing the audio file off to the
      // containing app (the usual scenario), we won't need these two frameworks
      // in our app extension.
      import AVFoundation
      import AVKit
      

      6b中。用以下内容替换整个override func viewDidLoad() {...}

      override func viewDidLoad() {
        super.viewDidLoad()
      
        // Get the item[s] we're handling from the extension context.
      
        // For example, look for an image and place it into an image view.
        // Replace this with something appropriate for the type[s] your extension supports.
      
        print("self.extensionContext!.inputItems = (self.extensionContext!.inputItems)")
      
        var audioFound :Bool = false
        for inputItem: AnyObject in self.extensionContext!.inputItems {
          let extensionItem = inputItem as! NSExtensionItem
          for attachment: AnyObject in extensionItem.attachments! {
            print("attachment = \(attachment)")
            let itemProvider = attachment as! NSItemProvider
            if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeMPEG4Audio as String)
              //|| itemProvider.hasItemConformingToTypeIdentifier(kUTTypeMP3 as String)
              // the audio format(s) we expect to receive and that we can handle
            {
              itemProvider.loadItemForTypeIdentifier(kUTTypeMPEG4Audio as String,
                  options: nil, completionHandler: { (audioURL, error) in
                NSOperationQueue.mainQueue().addOperationWithBlock {
      
                  if let audioURL = audioURL as? NSURL {
      
                    // in our sample code we just present and play the audio in our app extension
                    let theAVPlayer :AVPlayer = AVPlayer(URL: audioURL)
                    let theAVPlayerViewController :AVPlayerViewController = AVPlayerViewController()
                    theAVPlayerViewController.player = theAVPlayer
                    self.presentViewController(theAVPlayerViewController, animated: true) {
                      theAVPlayerViewController.player!.play()
                    }
      
                  }
                }
              })
      
              audioFound = true
              break
            }
          }
      
          if (audioFound) {
            break  // we only handle one audio recording at a time, so stop looking for more
          }
        }
      }
      

      6c所示。像上一步一样构建和运行。这一次,点击您的操作扩展程序将显示与以前相同的视图控制器,但现在覆盖了包含和播放录音的AVPlayerViewController实例。此外,我在代码中插入的两个print()语句应该提供类似于以下内容的输出:

      self.extensionContext!.inputItems = [<NSExtensionItem: 0x127d54790> - userInfo: {
          NSExtensionItemAttachmentsKey =     (
              "<NSItemProvider: 0x127d533c0> {types = (\n    \"public.file-url\",\n    \"com.apple.m4a-audio\"\n)}"
          );
      }]
      attachment = <NSItemProvider: 0x127d533c0> {types = (
          "public.file-url",
          "com.apple.m4a-audio"
      )}
      
      1. 对操作扩展程序Info.plist文件进行以下更改:
      2. 7a中。 Bundle display name默认为您为操作扩展程序指定的任何名称(在此示例中为MyActionExtension)。您可能希望将其更改为Save to MyApp。 (作为比较,Dropbox使用Save to Dropbox。)

        7b中。为密钥CFBundleIconFile插入一行,并将其设置为String类型(第二列),并将其值设置为MyActionIcon或其他类似值。然后,您需要提供相应的5个图标文件。在我们的示例中,这些将是:MyActionIcon.pngMyActionIcon@2x.pngMyActionIcon@3x.pngMyActionIcon~ipad.pngMyActionIcon@2x~ipad.png。 (对于iphone,这些图标应为60x60点,对于ipad,这些图标应为76x76点。仅使用Alpha通道确定哪些像素为灰色,RGB通道将被忽略。)将这些图标文件添加到您的应用扩展程序包中,而不是包含app的捆绑包。

        7C。在某些时候,您需要将键NSExtension > NSExtensionAttributes > NSExtensionActivationRule的值设置为TRUEPREDICATE以外的值。如果您希望仅为音频文件激活操作扩展,而不是为视频文件,pdf文件等激活,则可以在此处指定此类谓词。

        以上内容负责将语音备忘录录制到您的应用扩展程序。以下是如何从应用扩展程序到包含应用程序的录音的概述。 (如果时间允许的话,我以后会把它充实。)这篇博客文章(http://www.theappguruz.com/blog/ios8-app-groups)也可能有用。

        1. 设置您的应用以使用应用组。打开Project Navigator(Cmd-0)并单击第一行以显示您的项目和目标。选择应用的目标,点击&#34;功能&#34;选项卡,查找应用程序组功能,并将其开关设置为&#34; On&#34;。添加各种权利后,单击&#34; +&#34;登录以添加您的应用程序组,并为其命名为group.com.mycompany.myapp.sharedcontainer。 (它必须以group.开头,并且应该使用某种形式的反向DNS命名。)

        2. 对您的应用扩展程序目标重复上述操作,并为其命名(group.com.mycompany.myapp.sharedcontainer)。

        3. 现在,您可以从应用扩展程序端将音频录制的网址写入应用程序组的共享容器。在ActionViewController.swift中,替换实例化的代码片段,并使用以下内容显示AVPlayerViewController

          let sharedContainerDefaults = NSUserDefaults.init(suiteName:
              "group.com.mycompany.myapp.sharedcontainer")  // must match the name chosen above
          sharedContainerDefaults?.setURL(audioURL, forKey: "SharedAudioURLKey")
          sharedContainerDefaults?.synchronize()
          
        4. 同样,您可以使用以下内容从包含的应用程序中读取录音的网址:

          let sharedContainerDefaults = NSUserDefaults.init(suiteName:
              "group.com.mycompany.myapp.sharedcontainer")  // must match the name chosen above
          let audioURL :NSURL? = sharedContainerDefaults?.URLForKey("SharedAudioURLKey")
          
        5. 从这里,您可以将音频文件复制到应用程序的沙箱中,例如您应用的文档目录或您应用的NSTemporaryDiretory()。阅读此博客文章(http://www.atomicbird.com/blog/sharing-with-app-extensions),了解如何使用NSFileCoordinator以协调的方式执行此操作。

        6. 参考文献:

          Creating an App Extension

          Sharing Data with Your Containing App