與眾不同 windows phone (38) - 8.0 關聯啟動: 使用外部程序打開一個文件或URI, 關聯指定的文件類型或協議
作者:webabcd
介紹
與眾不同 windows phone 8.0 之 關聯啟動
- 使用外部程序打開一個文件
- 使用外部程序打開一個 Uri
- 關聯指定的文件類型
- 關聯指定的協議
示例
1、演示如何使用外部程序打開一個文件
AssociationLaunching/LaunchFile.xaml
<phone:PhoneApplicationPage x:Class="Demo.AssociationLaunching.LaunchFile" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel> <TextBlock Name="lblMsg" Margin="0 0 0 10" /> <Button Content="打開一個 .log 文件" Name="btnLaunchFile" Click="btnLaunchFile_Click" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
AssociationLaunching/LaunchFile.xaml.cs
/* * 演示如何使用外部程序打開一個文件 */ using System; using System.Windows; using Microsoft.Phone.Controls; using Windows.Storage; using System.IO; using System.Text; namespace Demo.AssociationLaunching { public partial class LaunchFile : PhoneApplicationPage { public LaunchFile() { InitializeComponent(); } private async void btnLaunchFile_Click(object sender, RoutedEventArgs e) { // 在 ApplicationData 的根目錄下寫一個 myLog.log 文件 StorageFolder applicationFolder = ApplicationData.Current.LocalFolder; StorageFile storageFile = await applicationFolder.CreateFileAsync("myLog.log", CreationCollisionOption.ReplaceExisting); using (Stream stream = await storageFile.OpenStreamForWriteAsync()) { byte[] content = Encoding.UTF8.GetBytes("hello webabcd"); await stream.WriteAsync(content, 0, content.Length); } // 啟動與 .log 類型文件關聯的默認應用程序,來打開指定的文件 Windows.System.Launcher.LaunchFileAsync(storageFile); } } }
2、演示如何使用外部程序打開一個 Uri(自定義協議)
AssociationLaunching/LaunchUri.xaml
<phone:PhoneApplicationPage x:Class="Demo.AssociationLaunching.LaunchUri" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel> <TextBlock Name="lblMsg" Margin="0 0 0 10" /> <Button Content="啟動一個協議名為 webabcd 的 uri" Name="btnLaunchUri" Click="btnLaunchUri_Click" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
AssociationLaunching/LaunchUri.xaml.cs
/* * 演示如何使用外部程序打開一個 Uri(自定義協議) */ using System.Windows; using Microsoft.Phone.Controls; using Windows.Networking.Proximity; namespace Demo.AssociationLaunching { public partial class LaunchUri : PhoneApplicationPage { public LaunchUri() { InitializeComponent(); } private void btnLaunchUri_Click(object sender, RoutedEventArgs e) { // 使用外部程序打開指定的 Uri(自定義協議,注意這里沒有“//”) Windows.System.Launcher.LaunchUriAsync(new System.Uri("webabcd:hello webabcd")); // nfc 方式啟用另一台 wp nfc 設備打開指定的 Uri(需要在 manifest 中聲明 ID_CAP_NETWORKING 和 ID_CAP_PROXIMITY) ProximityDevice nfcDevice = ProximityDevice.GetDefault(); if (nfcDevice != null) { long Id = nfcDevice.PublishUriMessage(new System.Uri("webabcd:hello webabcd")); } } } }
3、演示如何關聯指定的文件類型(即用本程序打開指定類型的文件)
AssociationLaunching/FileTypeAssociation.xaml
<phone:PhoneApplicationPage x:Class="Demo.AssociationLaunching.FileTypeAssociation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel> <TextBlock Name="lblMsg" TextWrapping="Wrap" /> <TextBlock TextWrapping="Wrap" Margin="0 10 0 0"> <Run>本程序可以打開 .log 類型的文件</Run> <LineBreak /> <Run>測試方法:通過 LaunchFile.xaml 打開一個 .log 類型的文件</Run> </TextBlock> </StackPanel> </Grid> </phone:PhoneApplicationPage>
AssociationLaunching/FileTypeAssociation.xaml.cs
/* * 演示如何關聯指定的文件類型(即用本程序打開指定類型的文件) * * * 由於配置為 NavUriFragment="fileToken=%s",所以本 app 打開某類型的文件會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動 * 相關的 UriMapper 參見 MyUriMapper.cs * * * 注: * 需要在 manifest 中增加類似如下的配置 * <Extensions> <!-- NavUriFragment="fileToken=%s" 的意思是: 1、某 app 啟動外部程序打開 .xxx 文件時會傳遞文件的 token 2、如果最終是由本 app 打開 .xxx 文件,則本 app 會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動 --> <FileTypeAssociation TaskID="_default" Name="myFileTypeAssociation" NavUriFragment="fileToken=%s"> <Logos> <!--相關類型的文件顯示在電子郵件附件中的圖標,33x33 像素,其會顯示在白色的背景前--> <Logo Size="small" IsRelative="true">Assets/AppIcon_33x33.png</Logo> <!--相關類型的文件顯示在 Office 中心列表視圖中的圖標,69x69 像素,其會顯示在白色的背景前--> <Logo Size="medium" IsRelative="true">Assets/AppIcon_69x69.png</Logo> <!--相關類型的文件顯示在瀏覽器下載中的圖標,176x176 像素,其會顯示在白色的背景前--> <Logo Size="large" IsRelative="true">Assets/AppIcon_176x176.png</Logo> </Logos> <SupportedFileTypes> <!--關聯的文件類型列表--> <FileType ContentType="text/plain">.log</FileType> <FileType ContentType="application/rar">.rar</FileType> </SupportedFileTypes> </FileTypeAssociation> </Extensions> */ using System; using System.Collections.Generic; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Windows.Phone.Storage.SharedAccess; using Windows.Storage; using Windows.Storage.Streams; using System.IO; using System.Text; namespace Demo.AssociationLaunching { public partial class FileTypeAssociation : PhoneApplicationPage { public FileTypeAssociation() { InitializeComponent(); } protected async override void OnNavigatedTo(NavigationEventArgs e) { IDictionary<string, string> queryStrings = this.NavigationContext.QueryString; if (queryStrings.ContainsKey("fileToken")) { // 獲取需要打開的文件的 token string fileToken = queryStrings["fileToken"]; // 保存需要打開的文件到本 app 的 ApplicationData await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder, "myLog2.log", NameCollisionOption.ReplaceExisting, fileToken); // 獲取文件的文件名稱 string fileName = SharedStorageAccessManager.GetSharedFileName(fileToken); lblMsg.Text = "fileName: " + fileName; lblMsg.Text += Environment.NewLine; // 獲取 ApplicationData 中指定的文件 StorageFolder applicationFolder = ApplicationData.Current.LocalFolder; StorageFile storageFile = await applicationFolder.GetFileAsync("myLog2.log"); // 顯示文件內容 IRandomAccessStreamWithContentType accessStream = await storageFile.OpenReadAsync(); using (Stream stream = accessStream.AsStreamForRead((int)accessStream.Size)) { byte[] content = new byte[stream.Length]; await stream.ReadAsync(content, 0, (int)stream.Length); lblMsg.Text += Encoding.UTF8.GetString(content, 0, content.Length); } } base.OnNavigatedTo(e); } } }
4、演示如何關聯指定的協議(即用本程序處理指定的協議)
AssociationLaunching/ProtocolAssociation.xaml
<phone:PhoneApplicationPage x:Class="Demo.AssociationLaunching.ProtocolAssociation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel> <TextBlock Name="lblMsg" TextWrapping="Wrap" /> <TextBlock TextWrapping="Wrap" Margin="0 10 0 0"> <Run>本程序可以處理 webabcd 協議</Run> <LineBreak /> <Run>測試方法:通過 LaunchUri 打開一個名為 webabcd 的協議</Run> </TextBlock> </StackPanel> </Grid> </phone:PhoneApplicationPage>
AssociationLaunching/ProtocolAssociation.xaml.cs
/* * 演示如何關聯指定的協議(即用本程序處理指定的協議) * * * 由於配置為 NavUriFragment="encodedLaunchUri=%s",所以本 app 打開某協議會通過 /Protocol?encodedLaunchUri=webabcd:xxxxxxxxxx 啟動 * 相關的 UriMapper 參見 MyUriMapper.cs * * * 注: * 需要在 manifest 中增加類似如下的配置 * <Extensions> <!-- Name 是協議名稱,對於本例來說協議的示例為“webabcd:hello webabcd”,注意其沒有“//” --> <Protocol TaskID="_default" Name="webabcd" NavUriFragment="encodedLaunchUri=%s" /> </Extensions> */ using System.Collections.Generic; using System.Windows.Navigation; using Microsoft.Phone.Controls; namespace Demo.AssociationLaunching { public partial class ProtocolAssociation : PhoneApplicationPage { public ProtocolAssociation() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 顯示協議的詳細信息 IDictionary<string, string> queryStrings = this.NavigationContext.QueryString; if (queryStrings.ContainsKey("protocol")) { lblMsg.Text = queryStrings["protocol"]; } base.OnNavigatedTo(e); } } }
自定義 UriMapper,用於處理當本 app 由文件打開或協議打開或鏡頭擴展打開或圖片擴展打開時,導航到相關的處理頁面
MyUriMapper.cs
/* * 自定義 UriMapper,用於處理當本 app 由文件打開或協議打開或鏡頭擴展打開或圖片擴展打開時,導航到相關的處理頁面 * * 注: * 要使此 UriMapper 有效,需要在 App.xaml.cs 中增加 RootFrame.UriMapper = new Demo.MyUriMapper(); */ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Windows.Navigation; using Windows.Phone.Storage.SharedAccess; namespace Demo { public class MyUriMapper : UriMapperBase { public override Uri MapUri(Uri uri) { string tempUrl = HttpUtility.UrlDecode(uri.ToString()); // 由文件啟動本 app 時會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動 if (tempUrl.StartsWith("/FileTypeAssociation")) { // 獲取 fileToken int fileTokenIndex = tempUrl.IndexOf("fileToken=") + 10; string fileToken = tempUrl.Substring(fileTokenIndex); // 獲取相關的文件名 string fileName = SharedStorageAccessManager.GetSharedFileName(fileToken); // myLog.log // 獲取相關的文件名的擴展名 string fileType = Path.GetExtension(fileName); // 根據文件類型的不同導航到不同的處理頁面 switch (fileType) { case ".log": return new Uri("/AssociationLaunching/FileTypeAssociation.xaml?fileToken=" + fileToken, UriKind.Relative); default: return new Uri("/MainPage.xaml", UriKind.Relative); } } // 由協議啟動本 app 時會通過 /Protocol?encodedLaunchUri=webabcd:xxxxxxxxxx 啟動 else if (tempUrl.StartsWith("/Protocol")) { // 獲取協議的詳細信息 int protocolIndex = tempUrl.IndexOf("encodedLaunchUri=") + 17; string protocol = tempUrl.Substring(protocolIndex); // 導航到處理 webabcd 協議的處理頁面 return new Uri("/AssociationLaunching/ProtocolAssociation.xaml?protocol=" + protocol, UriKind.Relative); } // 由鏡頭擴展啟動本 app 時會通過 /MainPage.xaml?Action=ViewfinderLaunch 啟動 else if (tempUrl.Contains("Action=ViewfinderLaunch")) { return new Uri("/CameraAndPhoto/LensExtensibility.xaml?fromLens=true", UriKind.Relative); } // 由圖片擴展之“共享...”啟動本 app 時會通過 /MainPage.xaml?Action=ShareContent&FileId={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 啟動 else if (tempUrl.Contains("Action=ShareContent")) { string fileId = tempUrl.Substring(tempUrl.IndexOf("FileId=") + 7).Replace("{", "").Replace("}", ""); return new Uri("/CameraAndPhoto/PhotoExtensibility.xaml?type=share&token=" + fileId, UriKind.Relative); } // 由圖片擴展之“編輯...”啟動本 app 時會通過 /MainPage.xaml?Action=EditPhotoContent&FileId={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 啟動 else if (tempUrl.Contains("Action=EditPhotoContent")) { string fileId = tempUrl.Substring(tempUrl.IndexOf("FileId=") + 7).Replace("{", "").Replace("}", ""); return new Uri("/CameraAndPhoto/PhotoExtensibility.xaml?type=edit&token=" + fileId, UriKind.Relative); } // 由圖片擴展之“自動上傳”啟動本 app 時會通過 /MainPage.xaml?Action=ConfigurePhotosUploadSettings 啟動 else if (tempUrl.Contains("Action=ConfigurePhotosUploadSettings")) { return new Uri("/CameraAndPhoto/PhotoAutoUpload.xaml?fromConfig=true", UriKind.Relative); } // 在鎖屏設置界面,如果將本 app 設置為背景提供程序,則鎖屏界面上會有一個名為“打開應用”的按鈕,點擊后會通過 /MainPage.xaml?WallpaperSettings=1 啟動本 app else if (tempUrl.Contains("WallpaperSettings=1")) { return new Uri("/Others/LockScreen.xaml?WallpaperSettings=1", UriKind.Relative); } return uri; } } }
將此 app 的 UriMapper 設置為我們自定義的 UriMapper
App.xaml.cs
private void InitializePhoneApplication() { // 設置本 app 的 UriMapper RootFrame.UriMapper = new Demo.MyUriMapper(); }
OK
[源碼下載]
