微软Windows Runtime App拥有很强的安全模型来防止不同App之间的数据获取和共享,也就是我们所说的"沙盒机制",每个App都运行在Windows沙盒中,App之间的数据是不会被别的App获取到的。
在UWP中,微软新增了GetPublisherCacheFolder —— 共享存储文件夹的机制,这个获取的共享存储文件夹并不是说打破了原有的"沙盒机制",而是指,同一个软件开发商发布的App之间,是允许访问一个共享的文件夹以及里面的内容。例如,多个应用程序使用相同的图片或者相同的自定义字体,你就可以将这些文件保存在共享存储文件夹中,再或者类似腾讯,腾讯可以把QQ用户的登录信息存储到共享文件夹中,方便于腾讯其他App(QQ空间、QQ音乐等)获取登录信息实现免登录功能。当然,微软的意见还是说让用户有权利了解并知情自己的哪些信息被存储到了共享存储空间中,并还拥有拒绝此操作的权利。
应用的共享存储文件夹将会伴随着第一次安装该开发商的App时创建(如果App使用了该特性)。当然共享存储文件夹也有限制和使用要求:
- 共享数据文件夹不能作为备份和漫游数据来使用,此外,用户有权利知情共享存储文件夹里面的数据。
- 不同的软件开发商之间是不能进行共享数据文件夹操作
- 不能把不同用户之间的数据存储到共享存储文件夹内,防止用户隐私被其他用户知情
- 共享存储文件夹没有版本控制机制
▲ 声明共享存储文件夹
首先,我们需要在App配置文件中声明这些共享存储文件夹名称,不需要提前创建好这些文件夹,系统会自己帮你创建。
<Package> … <Extensions> … <Extension Category="windows.publisherCacheFolder"> <PublisherCacheFolder> <Folder Name="Folder1"> <Folder Name="Folder2"> </PublisherCacheFolder> </Extension> … </Extensions> … </Package>
▲ 访问共享数据文件夹
我们可以调用GetPublisherCacheFolder方法获取共享数据文件夹:
StorageFolder sharedFonts = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("fonts");
然后使用StorageFolder类来操作共享存储文件和文件夹。
▲ 共享存储文件夹使用限制
- 共享存储文件夹中没有默认的子文件夹,你在调用GetpublisherCacheFolder 方法时必须填写要操作的文件夹名称
- 只允许访问配置清单中给出的文件夹
- 不允许访问共享存储文件夹的根目录文件夹
▲ 共享存储文件夹的清理
我们可以调用ClearPublisherCacheFolderAsync方法来明确指定要清理哪个子文件夹的文件或者哪个共享存储文件夹。共享文件夹自行删除是在卸载最后一个该开发商的App时发生的,共享文件夹是不受App应用程序保护的,当存在多个该开发商的App时,直到卸载最后一个,共享存储文件夹才会彻底被系统删除。
下面举个例子,我们在两个App中都声明使用共享存储文件夹,然后从App_A中存储一个字符串到共享存储文件夹中的一个文件,接着我们在App_B中来获取这个字符串,
App_A和App_B的UI Code 和 cs代码完全一致。
首先,创建一个UWP解决方案,然后创建两个项目
接着分别打开两个项目的Package.appxmanifest文件,添加对共享存储文件的声明:
1 <Extensions> 2 <Extension Category="windows.publisherCacheFolders"> 3 <PublisherCacheFolders> 4 <Folder Name="Folder1"/> 5 <Folder Name="Folder2"/> 6 </PublisherCacheFolders> 7 </Extension> 8 </Extensions>
然后在页面上创建一个文本框和两个按钮,如下:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBox x:Name="txtShare" Width="300"/> <StackPanel Orientation="Horizontal"> <Button x:Name="btnRead" Click="btnRead_Click" Margin="3" HorizontalAlignment="Left" Content="读取一个共享的值"/> <Button x:Name="btnSave" Click="btnSave_Click" Margin="3" HorizontalAlignment="Right" Content="写入一个共享的值"/> </StackPanel> </StackPanel> </Grid>
添加后台代码:
1 private async void btnSave_Click(object sender, RoutedEventArgs e) 2 { 3 if (string.IsNullOrEmpty(txtShare.Text.Trim())) return; 4 var sharedFolder1 = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("Folder1"); 5 6 var shareFile = await sharedFolder1.CreateFileAsync("share.txt", Windows.Storage.CreationCollisionOption.ReplaceExisting); 7 8 using (Stream stream = await shareFile.OpenStreamForWriteAsync()) 9 { 10 byte[] content = System.Text.Encoding.UTF8.GetBytes(txtShare.Text.Trim()+" From A "); 11 await stream.WriteAsync(content, 0, content.Length); 12 } 13 } 14 15 private async void btnRead_Click(object sender, RoutedEventArgs e) 16 { 17 var sharedFolder1 = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("Folder1"); 18 StorageFile shareFile = null; 19 try 20 { 21 shareFile = await sharedFolder1.GetFileAsync("share.txt"); 22 } 23 catch (Exception exc) 24 { 25 await new MessageDialog(exc.Message, "提示").ShowAsync(); 26 } 27 28 if (shareFile != null) 29 { 30 var accessStream = await shareFile.OpenReadAsync(); 31 using (Stream stream = accessStream.AsStreamForRead((int)accessStream.Size)) 32 { 33 byte[] content = new byte[stream.Length]; 34 await stream.ReadAsync(content, 0, (int)stream.Length); 35 36 txtShare.Text = System.Text.Encoding.UTF8.GetString(content, 0, content.Length); 37 } 38 } 39 }
为了区分两个App存进去的值,我在存储的时候给加上了App标志(A or B),来看下效果:
推荐一个UWP开发群:53078485 大家可以进来一起学习