UILocalNotifications 播放自定义声音

Posted

技术标签:

【中文标题】UILocalNotifications 播放自定义声音【英文标题】:UILocalNotifications playing Custom sound 【发布时间】:2011-08-18 04:53:18 【问题描述】:

我在我的应用程序中实现了本地通知,但我只是想知道是否有办法播放不属于 iPhone 应用程序主包的声音。 基本上在我的应用程序中,我希望用户录制在生成本地通知时播放的声音,而不是播放预先录制的或默认的声音。 据我所知,这是可以实现的,因为我在应用商店中看到了 2-3 个应用,它们正在做我想做的事情

- (void)alertSelector:(NSString *)AlertTitle WithFiringTime:(NSDate *)date
 

UILocalNotification *localNotification = [[[UILocalNotification alloc] init] autorelease];
   [localNotification setFireDate:date];
   [localNotification setTimeZone:[NSTimeZone defaultTimeZone]];
   NSDictionary *data = [NSDictionary dictionaryWithObject:date forKey:@"payload"];       
   [localNotification setUserInfo:data];[localNotification setAlertBody:AlertTitle];   
   [localNotification setAlertAction:@"View"]; [localNotification setHasAction:YES]; 
   localNotification.soundName=@"voice.aif"; 

   if (!localNotification)
          return;

    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 

【问题讨论】:

您能否链接到其中一个正在执行此操作的应用程序?谢谢。 @ArtGillespie 这是允许为 UILocalNotification 设置录制声音的众多应用之一。 itunes.apple.com/in/app/record-alarm-free/id418511936?mt=8 对我来说问题是因为我们有多个目标,而我添加的音频文件只添加到 1 个目标。基本上我必须将它添加到我们所有的目标中...... 【参考方案1】:

我的猜测是您的声音格式不适合操作系统播放。确保您的声音以 IMA4 格式格式化。另外,请确保您的文件在您的应用程序包中,您应该可以继续使用。

有关更多参考和类似问题,请参阅此 SO 问题。

Choose custom sound for Local Notifications

这是Apple's Local and Push Notification Guide 的链接。它详细解释了声音以及可以使用的默认声音。

【讨论】:

是否有任何代码可以按要求播放 UILocalNotification 的“Documents”目录中录制的声音? 我相信你只需要用 UILocalNotificaionDefaultSoundName 替换你的声音名称 我已经用另一个指向 Apple 文档的链接更新了我的答案,这应该可以帮助你。 正如问题中提到的“基本上在我的应用程序中,我希望用户录制在生成本地通知时播放的声音,而不是播放预先录制或默认的声音。至于我知道这是可以实现的,因为我在应用商店中看到了 2-3 个应用,它正在做我想做的同样的事情”你提到的页面没有任何设置录制声音的示例。由于一些应用程序会这样做,因此我们确信必须解决此问题。 这里有一些很好的信息。 tuaw.com/2007/08/06/iphone-coding-recording-audio【参考方案2】:

来自soundName属性的描述-

对于这个属性,指定一个文件名(包括扩展名) 应用程序主包中的声音资源或 UILocalNotificationDefaultSoundName 请求默认系统 声音。

似乎无法使用捆绑包中存在的声音以外的声音。您确定这些应用程序正在使用带有自定义声音的本地通知吗?也许他们正在播放带有警报的声音或类似的东西。

HTH,

阿克谢

【讨论】:

嗨 Akshay 谢谢您的回复,是的,我确定他们正在使用 UIlocalnotification 我应该给您这些应用程序的链接吗?他们是免费的应用程序,做着我想做的事情。我认为堆栈溢出不允许共享这些链接? 您是安排通知还是立即显示? 我正在使用 NSLocalnotification 安排它。 你能添加你用来显示通知的代码吗? - (void)alertSelector:(NSString *)AlertTitle WithFiringTime:(NSDate *)date UILocalNotification *localNotification = [[[UILocalNotification alloc] init] autorelease];[localNotification setFireDate:date]; [localNotification setTimeZone:[NSTimeZone defaultTimeZone]];NSDictionary *data = [NSDictionary dictionaryWithObject:date forKey:@"payload"]; [localNotification setUserInfo:data];[localNotification setAlertBody:AlertTitle]; [localNotification setAlertAction:@"View"]; [localNotification setHasAction:YES]; localNotification.soundName=@"voice.aif"; if (!localNotification) 返回;【参考方案3】:
notif.soundName = @"sound.caf";

应该可以。确保声音确实在您的应用程序包中,格式正确(线性 PCM 或 IMA4 — 几乎任何解释如何为 ios 转换声音的地方都会告诉您如何做到这一点),并且小于 30 秒。

您可以使用终端从 wav 和 mp3 转换:

afconvert -f caff -d LEI16@44100 -c 1 in.wav sound.caf

'in.wav' 是你要转换的输入声音,'sound.caf' 是输出文件,改变目录到你想要输出文件的地方

【讨论】:

【参考方案4】:

确保您的声音文件已添加到项目设置->(目标)->构建阶段下的“复制捆绑资源”列表中。 这为我解决了这个问题。起初我只得到默认声音,即使我指定了自定义文件名(并且文件已添加到项目中)。但在我手动将文件添加到此列表后,它开始工作。

我使用来自我的 mac 的系统声音进行测试。我在控制台中使用此命令对其进行了转换:

afconvert /System/Library/Sounds/Basso.aiff ~/Downloads/alert2.caf -d ima4 -f caff -v

【讨论】:

【参考方案5】:

好吧,我遇到了同样的问题,听起来以前不支持此功能,或者无法为 App Bundle 中未包含的本地通知播放自定义声音。但后来支持此功能,您可以从 App 容器中分配自定义声音,特别是在 Library/Sounds 目录中。它对我有用。您可以将声音从服务器下载到此目录,也可以通过将 .caf(Apple 表示其他扩展名可能有效)文件从 bundle 复制到 Library/sounds 目录来测试它,然后从 bundle 中删除该文件的引用,以便您可以确保如果播放的声音来自 bundle 之外的目录。这一切都很好,我的主要问题是,如果用户强制引用应用程序,它会停止为本地通知工作,而它仍然适用于推送工具包通知,我会在推送工具包推送到达时安排本地通知。 下面是测试目录播放声音的代码:

 func copyFileToDirectoryFromBundle()

    // get reference to library directory
    let LibraryDirectoryPaths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, true)

    // see what is in there 
    for path in LibraryDirectoryPaths
    
        print("di=\(path)")
    

    // prepare for sound directory
    let libraryDirectoryPath: AnyObject = LibraryDirectoryPaths[0]
    let soundsDirectoryPath = libraryDirectoryPath.stringByAppendingPathComponent("Sounds")

    // create sounds directory under library if not there already
    if !NSFileManager.defaultManager().fileExistsAtPath(soundsDirectoryPath)
    
    do 
        try NSFileManager.defaultManager().createDirectoryAtPath(soundsDirectoryPath, withIntermediateDirectories: false, attributes: nil)
        print("sounds library created,,,")
     catch let error as NSError 
        print("creating sounds directory error = \(error.localizedDescription)");
    
    
    else
    
        print("Sounds directory is there already under Library")
    

    do 
        // sounds directory should have been added under library
        let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL( NSURL(string: libraryDirectoryPath as! String)!, includingPropertiesForKeys: nil, options: [])
        print("Library directs=\(directoryContents)")


        // prepare for adding subdirectory with file name from bundle
        // here is where you should save files if downloaded from server 
        // here im just moving one from bundle 

        let subDirectoryPath = directoryContents.last!

        if let pathFromBundle = NSBundle.mainBundle().pathForResource("notification", ofType:"caf") 
            let myFilePathUnderSounds = "\(subDirectoryPath.path!)\("/notification.caf")"
            if !NSFileManager.defaultManager().fileExistsAtPath(myFilePathUnderSounds)
            
            do 
                print("bundle path=\(pathFromBundle)and datacontainer path=\(subDirectoryPath.path!)")
                try NSFileManager.defaultManager().copyItemAtPath(pathFromBundle, toPath:myFilePathUnderSounds )
                print("item copied")
             catch let error as NSError 
                print(error.localizedDescription);
            
            
            else
            
                print("Your file from bundle path = \(pathFromBundle) is already there under Sounds")
            
        
        else
        
            print("Item not found in bundle")
        

        // see item there after you add it
        let subDirectories = try NSFileManager.defaultManager().contentsOfDirectoryAtURL( subDirectoryPath, includingPropertiesForKeys: nil, options: [])

        print("files under sounds")
        for fileDirectory in subDirectories
        
            print(fileDirectory)
        

     catch let error as NSError 
        print(error.localizedDescription)
    


确保 .caf 文件位于 Library/Sounds 目录下。您所要做的只是将带有扩展名的文件名分配给本地通知 soundName 属性,就像文件在捆绑包中一样。

【讨论】:

【参考方案6】:

你在清理旧通知吗?

UIApplication* app = [UIApplication sharedApplication];
NSArray*  oldNotifications = [app scheduledLocalNotifications];
if ([oldNotifications count] > 0) 
    [app cancelAllLocalNotifications];

您也可以,从手机中删除应用程序(可能也需要重新启动) 它应该工作:-)

除此之外,上面提到的代码应该是正确的。 这条线localNotification.soundName=@"voice.aif"; 应该足以播放自定义声音。 但如果您先测试了通知而没有添加声音文件,则默认声音文件 (UILocalNotificationDefaultSoundName) 已注册!要重新注册,您必须取消之前的通知 (cancelAllLocalNotifications) 或删除应用程序,才能“重新”注册您的通知,

除此之外,苹果文档说:

不支持持续时间超过 30 秒的声音。如果你 指定一个声音超过 30 秒的文件,默认 而是播放声音。

希望它现在有所帮助:-)

【讨论】:

不相关——问题是关于如何让 UILocalNotification 播放自定义声音。

以上是关于UILocalNotifications 播放自定义声音的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 FCM 在 ios 推送通知中播放自定义通知声音

我想在 Firebase onMessage 接收方法上播放自定义通知音,当锁定屏幕 android 手机时

使用 Cloud Functions 播放自定义通知声音 - iOS

打开/关闭所有 UILocalNotifications

获取现有 UILocalNotifications 的列表并修改其日期

UILocalNotifications 和 applicationIconBadgeNumber 的良好模式