随着 Windows 10 发布的,将来 Windows 平台都是统一开发模型,能够只写一个 Appx 包,就能够同时部署到html
Windows/ Windowsw Phone/ Tablet /xbox ..平台上了,咱们几个 Windows 组的同事也是摩拳擦掌,但愿写一html5
个用户体验很好的客户端。git
看了一下 MSDN 最新发布的文档和视频教程,这里做为笔记,大概总结了一下在 Windows 10上,针对 Windows 8.1github
和 WP 上的一些技术更新。web
贴一张视频里面聚合的路线图:windows
文档内容有点长,下面截取了几处要点翻译了一下:浏览器
1)经过 Windows Universal Platform(UAP)统一的 API (Windows Runtime)和一些响应式的 UI 控件,服务器
可让你只写一个 app ,即可以安装到各类设备上。app
2)PC 运行的是桌面操做系统,基于传统的桌面家族。手机、平板等设备,运行的是 mobile 操做系统,基于的是移动
设备家族。
3) Windows 10 提供了新的 universal 控件,导航面板 和开发工具来帮助你面向多种设备进行开发。例如,你能够利用
多种不一样屏幕的分辨率来适配你的手机或者电脑的 UI。
4)Windows Phone 上的 Pivot 控件,如今提供给了 universal 设备上
5)在 XAML 页面可使用 StateTriggers 来触发页面的 visual state 变换。它能够经过窗口尺寸的变化,来直接改变布局、元素
的属性,而不须要在 C# 页面写逻辑进行 VisualStateManager 进行管理。 (相似于 Web 上 CSS 中的 @media ,来实现响应式布局)
6) 一个新的 UI 共享代码的方式,XAML 文件能够共享一个单独的 code-behind 文件了。
7)在选择目标设备的SDK 时,能够直接经过 “项目” -> “引用” 的方式直接添加(与引用类库相似)。添加目标设备的 SDK(选择 Project > Add Reference >
Universal App Platform > Extensions 添加相应的 SDK)。
8)使用这个方法 ApiInformation.IsApiContractPresent (Windows.Foundation.Metadata.ApiInformation class)检测 api 是否支持,
不只仅是使用条件编译了。由于有的 api 只有个别设备可使用,例如,手机上的相机实体按键 api。
下面一些内容翻译自视频教程里面的 ppt。
一、Win 8.1 工程 -> Win 10 工程的调整
1) App 生命周期、后台任务、Tiles 和 toasts 彻底同样
2) UAP APIs 是 Windows 8.1 WinRT APIs 的超集 (UAP : universal app platform)
3) 可使用适应性代码(adaptive code)判断运行的平台,以替换预编译语句:
例如,以前使用:
#if WINDOWS_PHONE_APP // wp 平台的 api 调用 #elif WINDOWS_APP // win pad 平台的 api 调用 #endif
能够替换为 ApiInformation 类进行判断:
// 判断是不是具备实体按键(Back键、Camera 键..) if(Windows.Foundation.Metadata.Apilnformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) { // Windows phone 的相关 api }
// Windows.Foundation.Metadata.ApiInformation 类提供的静态方法:
// IsApiContractPresent // IsEnumNamedValuePresent // IsEventPresent // IsMethodPresent // IsPropertyPresent // IsReadOnlyPropertyPresent // IsTypePresent // IsWriteablePropertyPresent
4) 一些 APIs 被弃用了( 好比 phone 8.1 的文件选择 …AndContinue APIs)
5) 桌面右侧的 Charms 被移出了,因此 app 必须提供 UI 来加载 Settings、Share 和 Search。
相关代码逻辑和以前彻底同样,不须要修改
5) 替换一些有的工程没有定义的系统样式:好比: PhoneAccentBrush
6) 建立一个响应式的 UI:
Phone/narrow view:
small landscape view:
large landscape view:
8) 添加了新控件:Relative Panel、SplitView(Splitview.Content 的属性有意设置为 Frame)
就像 Windows10 上面的 “计算器”,就是 SplitView控件。在单击左上角的 “汉堡包” 按钮,弹出切换菜单:
Win pad 和 win phone 商店里的 Xbox One SmartGlass 猜想是一个 UAP 包了,在 phone 上的效果:
二、编译指令
// C# Syntax #if WINDOWS_PHONE_APP Windows.Phone.UI.Input.HardwareButtons.BackPressed += this.HardwareButtons_BackPressed; #endif
// C++ Syntax #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
_backPressedEventToken = HardwareButtons::BackPressed += ref new EventHandler<BackPressedEventArgs^> (this,&NavigationHelper::HardwareButton_BackPressed); #endif
三、支持的平台的 SDK,能够直接经过项目引用进行添加:
四、Segoe MDL2 字体图标资源,更丰富的图标字体可使用:
前段时间,写过图标资源的文章: 0二、Universal app 中按钮图标使用
五、Visual State 可使用 setters 和 triggers 直接在 XAML 中进行样式的属性的赋值。相似于
Web 上的 CSS媒体查询语法(好比,@media (min-width:800px) and (max-width:1200px) { ... })。
从而不须要再 C# 页面经过 VisualStateManager 进行视图状态的切换。例以下面,当窗口大于 600px 时,
StackPanel 对象为横向布局:
<VisualState x:Name="wideState"> <VisualState.Setters> <Setter Target="myPanel.Orientation" Value="Horizontal" /> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="600"/> </VisualState.StateTriggers> </VisualState>
触发器的参数(Trigger types):
MinWindowWidth
MinWindowHeight
六、App 与 App 的通讯:
1)在 Windows 8.1 时:URI 和 Protocol Activation/Share Contract
2)在 Windows10 UAP:
a) 启动一个指定的 app :
var options = new LauncherOptions(); options.TargetApplicationPackageFamilyName = "24919.InstapaperIt";
var launchUri = new Uri("instapaper:?AddUrl=http%3A%2F%2Fbing.com"); await Launcher.LaunchUriAsync(launchUri, options);
b) 向另外一个 app 发送数据;经过向另外一个app 发送一个文件 token 的方式,以
向另外一个 app 传递本身的文件:
var options = new LauncherOptions(); options.TargetApplicationPackageFamilyName = "24919.InstapaperIt"; var token = SharedStorageAccessManager.AddFile(gpxFile); ValueSet inputData = new ValueSet(); inputData.Add("Token", token); var launchUri = new Uri("instapaper:?AddUrl=http%3A%2F%2Fbing.com"); await Launcher.LaunchUriAsync(launchUri, options, inputData);
c) Launch for Results:启动另外一个 app,并得到其返回结果:
// 一个 app var options = new LauncherOptions(); options.TargetApplicationPackageFamilyName = "24919.Instap"; var launchUri = new Uri("instapaper:?AddUrl=http%3A%2F%2Fbing.com"); await Launcher.LaunchUriForResultsAsync(launchUri, options, data); // 另外一个 app,把结果存到 ValueSet 字典中,返回 var resultData = new ValueSet(); resultData.Add("Result", value); operation.ProtocolForResultsOperation.ReportCompleted(resultData);
d) 判断当前设备上是否有指定 app (Query URI Support. Discover if app already installed to handle a Uri):
// 判断当前设备上,是否有 app 声明了instapaper 启动协议名称 var queryUri = new Uri("instapaper:"); await Launcher.QueryUriSupportAsync(queryUri, LaunchUriType.LaunchUri); // 判断当前设备上,是否有 app 声明了instapaper 启动协议名称,而且它的 pfn 为 "24919.InstapaperIt" 的指定app var queryUri = new Uri("instapaper:"); string packageFamilyName = "24919.InstapaperIt"; await Launcher.QueryUriSupportAsync(queryUri, LaunchUriType.LaunchUriForResults, packageFamilyName);
e) 来自同一个发布者(同一个开发者帐号)的多个 app,可 Share 同一个存储文件夹 和设置(files and settings)。
须要在 app 的清单件中声明一个子文件夹,当系统安装 app 时,会自动建立的:
<Package> <Extensions> <Extension Category="windows.publisherCacheFolder"> <PublisherCacheFolder> <Folder Name="folder1"> </PublisherCacheFolder> </Extension> </Extensions> </Package>
在 app 中获取这个文件夹:
// 获取这个共享的文件夹 Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("folder1"); // 清空共享文件夹 Windows.Storage.ApplicationData.Current.ClearPublisherCacheFolderAsync();
e) App Services:经过后台任务的方式,一个app 能够做为一个本地轻量级的 Web Service
供其它 app 调用。
七、Drag 和 drop
在之前的 XAML 上,拖、拽操做比较局限,只有特定控件(GridView、ListView)有拖拽事件:
<GridView AllowDrop="true" DragEnter="contactGridView_DragEnter" DragLeave="contactGridView_DragLeave" DragOver="contactView_DragOver" Drop="contactGridView_Drop"/>
在 UAP 上添加了新的拖、拽 API,能够实现 app 之间的拖放,好比:
1)ListViewBase.DragItemsCompleted
2)UIElement.DragAsync()
3)扩展的 DragEventArgs 参数
八、编译时的数据绑定
XAML 中的 Data Binding 会影响性能,动态类型和反射是部分缘由。解决方案是编译时(Compile-time binding)
的绑定。优势是全面快速的实例化,高效的 change 侦测和 UI 更新,编译时错误(Compile-time errors)
<!--示例--> <ListView ItemsSource="{x:Bind Groups}" > <ListView.ItemTemplate> <DataTemplate TargetType="data:BookItem" > <TextBlock Text="{x:Bind Book.Title}" /> </DataTemplate> </ListView.ItemTemplate> </ListView>
九、Transform 3D, 很像 CSS 中的 “preserve-3d”
Transform 3D 不会影响子元素的 transforms
1)现有的变换属性(Composite transform):
Translate Transform (move)
Scale Transform (size)
Rotate Transform (angle)
Skew Transform (shape)
Render Origin
利用 Projection 属性(Rotate X/Y/Z) 模拟 3D 效果
2) UAP 中添加了新属性 UIElement.Transform3D:
容器:
Container.PerspectiveTransform3D
Depth
OffsetX
OffsetY
子元素:
Child.CompositeTransform3D
Rotation
Scale
Translate
<Grid Width="300" Height="200"> <Grid.Transform3D> <PerspectiveTransform3D OffsetX="-150" OffsetY="-100" Depth="1000" /> </Grid.Transform3D> <Grid Background="Red"> <Grid.Transform3D> <CompositeTransform3D RotationY="30" TranslateZ="1"/> </Grid.Transform3D> </Grid> <Grid Background="Blue"> <Grid.Transform3D> <CompositeTransform3D RotationX="-30" TranslateZ="-1"/> </Grid.Transform3D> </Grid> </Grid>
十、 App Services:
1) UAP 提供了不少 API 来使 app 之间互相通讯:
Windows.ApplicationModel.Contacts
Windows.ApplicationModel.Email
Windows.System.Launcher.LaunchUriAsync 启动h settings, maps, store 等…
其它…
2)UAP 容许 app 之间互相通讯:
· Uri 关联,使用 LaunchUriAsync 启动
· File 关联,使用 LaunchFileAsync 启动
· Launch 并获取结果,使用 LaunchUriForResultsAsync
· App Services:用来做为灵活、轻量级的,相似于 web REST 服务:
a、简单的请求、响应消息 api
b、以 string-keyed 形式(ValueSet 类型) 数据包传递
c、易于使用和多个不一样的载荷
3)App Services – Client 示例:
AppServiceConnection connection = new AppServiceConnection(); connection.AppServiceName = "microsoftDX-appservicesdemo"; connection.PackageFamilyName = "24919ArunjeetSingh.InstapaperIt"; AppServiceConnectionStatus connectionStatus = await connection.OpenAsync(); if (connectionStatus == AppServiceConnectionStatus.Success) { //向服务端发送数据 var message = new ValueSet(); message.Add("Command", "CalcSum"); message.Add("Value1", Int32.Parse(Value1.Text)); message.Add("Value2", Int32.Parse(Value2.Text)); // 发送消息并等待响应 AppServiceResponse response = await connection.SendMessageAsync(message); if (response.Status == AppServiceResponseStatus.Success) { int sum = (int)response.Message["Result"]; new MessageDialog("Result=" + sum).ShowAsync(); } } else { //若是没有 app service 端,则指导用户下载 app service 端 }
App Services – Service:
namespace AppServicesDemoTask { // 须要继承 IBackgroundTask 接口 public sealed class AppServiceTask : IBackgroundTask { private static BackgroundTaskDeferral _serviceDeferral; public void Run(IBackgroundTaskInstance taskInstance) { // 注册当先后台任务的 取消事件 taskInstance.Canceled += TaskInstance_Canceled; // 得到任务实例的 deferal 对象 _serviceDeferral = taskInstance.GetDeferral(); var appService = taskInstance.TriggerDetails as AppServiceTriggerDetails; if (appService.Name == "microsoftDX-appservicesdemo") { // 能够添加调用 app 的合法性验证 ValidateCaller(appService.CallerPackageFamilyName) ?? appService.AppServiceConnection.RequestReceived += RequestReceived; } } ... private async void RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { var message = args.Request.Message; // 服务端使用 Command 参数,做为 client 调用的操做 string command = message["Command"] as string; switch (command) { case "DoIt": { var messageDeferral = args.GetDeferral(); int value1 = (int)message["Value1"]; // ... 作一些处理 //向调用者返回结果 var returnMessage = new ValueSet(); returnMessage.Add("Result", result); var responseStatus = await args.Request.SendResponseAsync(returnMessage); messageDeferral.Complete(); break; } case "Quit": { // 服务端被要求退出,则调用deferral 对象的 Complete 方法,系统终止 Service _serviceDeferral.Complete(); break; } } }
4) 在清单文件中声明 App Service:
<?xml version="1.0" encoding="utf-8"?> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"> <Applications> <Application Id="App“> <Extensions> <uap:Extension Category="windows.appService“ EntryPoint="AppServicesDemoTask.AppServiceTask"> <uap:AppService Name="microsoftDX-appservicesdemo" /></uap:Extension> </Extensions> </Application> </Applications> <Capabilities> <Capability Name="internetClient" /> </Capabilities> </Package>
5)双向通讯 :Client 和 server 均可以发送和接收消息
Client 和 server 能够保持双向通讯的 channel 打开着。Client 端能够给本身
AppServiceConnection 实例注册一个 RequestReceived 事件
AppServiceConnectionStatus connectionStatus = await connection.OpenAsync(); if (connectionStatus == AppServiceConnectionStatus.Success) { connection.RequestReceived += OnRequestReceived; }
6)在调试的时候能够经过 Package.Current.Id.FamilyName 属性得到包的 PFN:
7)App Service 生命周期:
· Server 端的后台任务经过设置 AppServiceTrigger 条件启动
· Client 端能够经过调用 AppServiceConnection 对象的 dispose方法,或者发送指示命令来关闭 Service 端
· 若是 Client 端被挂起,则相应的 Service app 会被关闭
· 当系统资源紧张会致使 Launch 失败或者 Service 被关闭:服务端得到 AppServiceConnectionStatus.ResourcesNotAvailable消息;
当发送消息时得到 AppServiceResponseStatus.ResourceLimitsExceeded
十一、消息中心 Action Center Management APIs:
1)管理 app 的通知,开发者能够:
· 移出一个或多个通知
· 给 notification 通知添加标签和分组
· 替换为一个新的 notification
· 设置一个 notification 的过时时间
· 发送一个 “Ghost Toast” notification(只显示在通知中心,但不弹给用户)
2)每一个 app 最多在通知中心有 20条通知。最长保存7天(或者更短)
用户能够:
· 追踪(单击)一个通知(从通知中心移出)
· 移出一组通知
· 移出全部通知
3)后台任务触发器(ToastNotificationHistoryChangedTrigger)
当用户从消息中心解除一个 notification 或者一个 app 添加、移出、替换
一个notification 时触发。
使用这个触发器任务,app 能够保持 Toast 、Tile 消息通知的一致性。好比,
用户移出了消息中心的 通知时,tile 上的相关消息也须移出:
// 使用 ToastNotificationHistoryChangedTrigger 触发器的后台任务 public sealed class ActionCenterChangedTask: IBackgroundTask { public void Run(IBackgroundTaskInstance taskInstance) { var toasts = ToastNotificationManager.History.GetHistory(); if (toasts != null) { var count = toasts.Count(); if (count== 0) { BadgeUpdateManager.CreateBadgeUpdaterForApplication().Clear(); } else { XmlDocument badgeXml = BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeNumber); XmlElement badgeElement = (XmlElement)badgeXml.SelectSingleNode("/badge"); badgeElement.SetAttribute("value", count.ToString()); BadgeNotification badge = new BadgeNotification(badgeXml); BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(badge); } } } }
十二、Web 平台(Sparta 浏览器)
有关 Web 更新有不少,具体视频上讲的很详细。这里只列出一点。
从 Windows 8 开始,已经可使用 html5/js 的方式开发 native app 了,而且不是经过 WebView 控件,
而是直接经过 JS 调用 Windows Runtime 的 api,可是不容许从 appx 包外的 JS 调用。到了 Windows 10
的 UAP,则去掉了这个限制,甚至能够经过在 app 的清单文件中,指定服务器端的地址,直接下载到本地执行逻辑,
调用 runtime 的 api。经过这种方式,很容易实现各类功能扩展。
清单文件添加服务器端的地址:
<uap:ApplicationContentUriRules> <uap:Rule Type="include" WindowsRuntimeAccess="all" Match="https://rjs.azurewebsites.net/" /> <uap:Rule Type="include" WindowsRuntimeAccess="allowForWebOnly" Match="https://*.facebook.com/" /> <uap:Rule Type="include" WindowsRuntimeAccess="none" Match="http://bing.com/" /> <uap:Rule Type="include" Match="https://*.microsoft.com/" /> </uap:ApplicationContentUriRules>
W3C 标准 Manifest for Web Apps:http://w3c.github.io/manifest/