UWP学习(四) -- Naïve MondrianPlayer Pro
2018-04-15
成果展示
在线播放
缓存的资源
技术问题 作为naive player1.0 的升级版,这一次主要加入两个功能,即在线媒体资源的播放和缓存。有了互联网的活力使它不再那样Naive。做完之后确实觉得:我的播放器终于有那么一丢丢流动的血液了..
下面介绍本次作业遇到的技术问题。
1. 播放在线url资源 在开始做这部分功能之前,我认为这可能是最复杂的一部分,我需要解析url吗?怎么提到url里面的媒体文件呢…边缓存边播放是怎么做到的呢?但是我记得老师上课说过这部分非常简单,所以一定是我想多了。之后知道了我们要实现就是uri资源的播放,这一下就简单很多了,既定的mediaPlayer.source一下就有着落了。先不管其他的,查一波微软官方uri文档再说。
Uri文档:https://docs.microsoft.com/en-us/uwp/api/windows.foundation.uri
https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.mediaplayerelement
1 2 3 MediaPlayerElement mediaPlayerElement1 = new MediaPlayerElement(); mediaPlayerElement1.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Media/video1.mp4")); mediaPlayerElement1.AutoPlay = true;
通过这一段代码我找到了实现方法,于是很容易写出了我的代码:
1 2 3 4 5 6 7 8 9 var media_url = url_input.Text.Trim(); //去掉uri里的空格 string str = media_url.Substring(media_url.Length - 3); string str1 = media_url.Substring(0, 4); if(!string.Equals(str1,"http")) { media_url = "http://" + media_url; } my_player.Source = MediaSource.CreateFromUri(new Uri(media_url)); //媒体源设置为uri源 my_player.MediaPlayer.Play();
这里还得注意一个坑:uri资源链接头部若不是以http开头的话,解析uri媒体源的时候会炸掉!所以以www或者其他形式开头的,为了兼容性更强,请务必编程手动加上‘http://’的协议header。
写完后迫不及待贴一个mp4的uri进去试试!哇,我的naive player也让可以在线播放视频了。。 至于之前想的怎么边缓存边播放?这一切原来MediaPlayerElement都已经封装实现好了,不需要我瞎操心,棒。 第一个大任务完成。
2. 下载资源 第二个大任务,缓存uri媒体资源。首先我想我得找到下载这个文件的方法,然后再使用根文件写入相关的类把文件写到指定文件夹,就实现了缓存。 首先在微软官方文档发现了一个叫BackgroundTransfer的东西,不认识啊,不过看示例代码似乎很靠谱。先贴过来试了一下。
https://docs.microsoft.com/en-us/uwp/api/windows.networking.backgroundtransfer.downloadoperation
示例代码:
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 using Windows.Foundation; using Windows.Networking.BackgroundTransfer; using Windows.Storage; private async void StartDownload_Click(object sender, RoutedEventArgs e) { try { Uri source = new Uri(serverAddressField.Text.Trim()); string destination = fileNameField.Text.Trim(); StorageFile destinationFile = await KnownFolders.PicturesLibrary.CreateFileAsync( destination, CreationCollisionOption.GenerateUniqueName); BackgroundDownloader downloader = new BackgroundDownloader(); DownloadOperation download = downloader.CreateDownload(source, destinationFile); // Attach progress and completion handlers. HandleDownloadAsync(download, true); } catch (Exception ex) { LogException("Download Error", ex); } }
emm结果,不好使。网上也不好找这个类的使用方法实例,我准备弃坑了..投入经典的HttpClient怀抱吧..
http https://docs.microsoft.com/en-us/uwp/api/windows.web.http.httpclient
后来还是发现我太菜了,看不懂。为什么就没有一个完美的实例呢。。。微软文档为了照顾他们实现的类的多种强大接口,超级多的接口示例,且每个接口文档就一小段,但是我只想要一个最naive最simple和完整的,把一个故事讲好怎么就这么难呢。除了微软爸爸, 还好我有外援https://www.cnblogs.com/T-ARF/p/5886153.html
保障先放在这里,继续去看写入文件夹相关实现。
3. 缓存到指定目录 搞定了下载,再找到写文件到指定文件夹的方法就完成基本任务了。 继续官方文档走起。
https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-managing-folders-in-the-music-pictures-and-videos-libraries
示例代码:
1 2 3 StorageFolder storageFolder = KnownFolders.PicturesLibrary; StorageFile file = await storageFolder.CreateFileAsync("sample.png", CreationCollisionOption.ReplaceExisting); // Do something with the new file.
这次体验很不错,因为无意中发现了KnownFolders.PictureLibrary这个东西。这难道不像要求的指定到Music文件夹吗??我觉得我只要将PictureLibrary换成MusicLibrary就行了。发现新大陆真是太好,开始以为要进行一堆字符串匹配文件夹名呢.. 迅速去KnownFolders走一波:
https://docs.microsoft.com/en-us/uwp/api/Windows.Storage.KnownFolders#Windows_Storage_KnownFolders_MusicLibrary
先不高兴太早,坑又来了。权限问题。不会解释了,直接到Packages.appxanifest>功能>音乐 打上勾吧。。我很懵逼。(这一点是问了同学才知道的)
添加完权限后,我的实现代码:
1 2 3 4 5 6 7 var uri = url_input.Text.Trim(); //获取在线文件uri var media_url = new Uri(uri); var MusicFileLocation = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Music); //定位到默认Music文件夹 var MusicFolder = MusicFileLocation.SaveFolder; //将Music设为读入文件目录 var file_name = Path.GetFileName(media_url.LocalPath); StorageFile music_file = await MusicFolder.CreateFileAsync(file_name, CreationCollisionOption.FailIfExists);
整合以上两部分,所以从下载资源到将文件写入到指定目录(Music)的完整代码为: 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 async private Task Download_Save_media() { var uri = url_input.Text.Trim(); var media_url = new Uri(uri); //媒体下载源 var MusicFileLocation = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Music); //获取本地Music文件夹路径 var MusicFolder = MusicFileLocation.SaveFolder; //设置Music文件夹为写入文件夹 var dialog = new ContentDialog() { Title = "提示", Content = "下载情况", PrimaryButtonText = "确定", // SecondaryButtonText = "取消", FullSizeDesired = false, }; try { var file_name = Path.GetFileName(media_url.LocalPath); //设置写入媒体文件名 StorageFile music_file = await MusicFolder.CreateFileAsync(file_name, CreationCollisionOption.FailIfExists); if (music_file != null) { HttpClient httpClient = new HttpClient(); IBuffer buffer; try { buffer = await httpClient.GetBufferAsync(media_url); await FileIO.WriteBufferAsync(music_file, buffer); //写入指定目录 dialog.Content = "下载完成!"; dialog.PrimaryButtonClick += (_s, _e) => { }; await dialog.ShowAsync(); } catch (Exception ex) { dialog.Content = "未找到下载源! 下载失败"; dialog.PrimaryButtonClick += (_s, _e) => { }; await dialog.ShowAsync(); } } } catch (Exception ex) { dialog.Content = "下载失败!未找到下载源或已存在文件"; dialog.PrimaryButtonClick += (_s, _e) => { }; await dialog.ShowAsync(); Debug.WriteLine("A file has existed."); } }
4. 从缓存目录读取资源 稍微扩展一下,让用户可以直接播放刚才缓存的文件。
其实之前的FileOpenPicker技术和代码就能完全解决,只是需要增加默认打开Music那个缓存文件目录这个特性。 继续参考FileOpenPicker这个文档:
https://docs.microsoft.com/en-us/uwp/api/Windows.Storage.Pickers.FileOpenPicker
这次收获依然很佳。发现了openPicker.SuggestedStartLocation这个东西。这就是选择推荐打开的文件夹,很棒。这段示例代码赞一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 FileOpenPicker openPicker = new FileOpenPicker(); openPicker.ViewMode = PickerViewMode.Thumbnail; openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; openPicker.FileTypeFilter.Add(".jpg"); openPicker.FileTypeFilter.Add(".jpeg"); openPicker.FileTypeFilter.Add(".png"); StorageFile file = await openPicker.PickSingleFileAsync(); if (file != null) { // Application now has read/write access to the picked file OutputTextBlock.Text = "Picked photo: " + file.Name; } else { OutputTextBlock.Text = "Operation cancelled."; }
很容易的,我的代码:
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 async private Task choose_cache() { FileOpenPicker openPicker = new FileOpenPicker(); openPicker.FileTypeFilter.Add(".mp3"); openPicker.FileTypeFilter.Add(".wma"); openPicker.FileTypeFilter.Add(".mp4"); openPicker.FileTypeFilter.Add(".wmv"); //设置推荐文件夹为缓存路径Music文件夹 openPicker.SuggestedStartLocation = PickerLocationId.MusicLibrary; var file = await openPicker.PickSingleFileAsync(); if (file != null) { //播放器标题栏设为文件名,文件名可通过file的属性值直接获取 media_title.Text = file.Name; my_player.Source = MediaSource.CreateFromStorageFile(file); my_player.MediaPlayer.Play(); Debug.WriteLine(file.FileType); if(file.FileType == ".mp3" || file.FileType ==".wma" ) { mp3_logo.Opacity = 1; } else if(file.FileType == ".mp4" || file.FileType == ".wmv") { mp3_logo.Opacity = 0; } hideWelcomeUI(); } }
5. 其他技术 至此,所以功能全部完成,加鸡腿。但是下载的时候没有提示,下载出现的异常也没有提示,似乎有点不人性化。所以加一个Dialog吧。搜索了解到uwp dialog主要有messageDialog和contentDialog,这里使用contenDialog。
https://www.cnblogs.com/TianFang/p/4857205.html 示例代码很简单,直接贴上我的代码:
1 2 3 4 5 6 7 8 9 var dialog = new ContentDialog() { Title = "提示", Content = "下载情况", PrimaryButtonText = "确定", FullSizeDesired = false, }; dialog.PrimaryButtonClick += (_s, _e) => { }; await dialog.ShowAsync();
挖个小坑,下次加入下载进度条提示的功能。
⬅️ Go back
为正常使用来必力评论功能请激活JavaScript