应用开发中,开发者时常需要获取一些系统、用户信息用于数据统计遥测、问题反馈、用户识别等功能。本文旨在介绍在 Windows UWP 应用中获取一些常用系统、用户信息的方法。示例项目代码可参见 Github:
由于涉及内容较多,故本文会分为多篇展开。本篇介绍获取设备和系统的基本信息、应用包信息、用户数据账户信息和用户账户信息。
原博客阅读地址:http://validvoid.net/uwp-system-info-collect-1/
AnalyticsInfo
Windows.System.Profile
命名空间下的 AnalyticsInfo 类负责提供用于设备分析的相关信息。通过此类,我们能够获得系统的具体版本号以及设备类型等信息。
通过 AnalyticsInfo
类中的 VersionInfo
属性我们可以获取当前应用运行设备的设备类型和操作系统具体版本。AnalyticsVersionInfo 类型的 VersionInfo
属性包含两个成员:
DeviceFamily
属性的返回值类型为字符串。其提供的设备类型信息极为重要,几乎在所有 UWP 开发中均会用到。通常我们都会根据此属性返回的设备类型信息配合实现应用的响应式设计。例如,返回 "Windows.Desktop" 时表示应用运行在桌面端 Windows 10 上,则应用呈现适合于鼠标键盘操作的 PC 端界面;返回 "Windows.Mobile" 时表示应用运行在移动端的 Windows 10 上,则应用应当呈现适合于触屏操作的移动端小屏界面。
DeviceFamilyVersion
属性的返回值类型也是字符串。其返回值指示了当前设备运行的 Windows 的具体版本号。不过直接获取此属性拿到的返回值是一个形如 "2814750460870692" 的 long 型数字。如果想要获取可读的 "major.minor.revision.build" 形式的版本号,需要先将此数值转化为十六进制,然后进一步转化为可读的版本号。
格式化版本号的 C# 代码:
string sv = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
ulong v = ulong.Parse(sv);
ulong v1 = (v & 0xFFFF000000000000L) >> ;
ulong v2 = (v & 0x0000FFFF00000000L) >> ;
ulong v3 = (v & 0x00000000FFFF0000L) >> ;
ulong v4 = (v & 0x000000000000FFFFL);
string version = $"{v1}.{v2}.{v3}.{v4}";
运行示例代码会得以类似以下内容的输出:
Device Analytics Info DeviceForm: Unknown
DeviceFamily: Windows.Desktop
DeviceFamilyVersion: 2814750460870692
Reconstructed OS Version: 10.0.10586.36
需要指出的是,如果你打算通过 DeviceFamilyVersion 进行数据统计、分析工作,那么在应用的客户端代码中不要将原始的 DeviceFamilyVersion 返回值格式化为可读形式。据微软官方人员在 MSDN 的解释,AnalyticsInfo.VersionInfo
旨在为遥测和日志记录提供一个不透明的版本号字符串值,最佳做法是将该原始值传回服务器,如果有必要,在服务器端进行格式化解析的工作。
另外,AnalyticsInfo
类中的 DeviceForm
属性具体作用不明,在 PC 和 Windows Mobile 设备中均返回 "Unknown"。MSDN 文档中仅将此属性描述为 "Gets the device form."
资源限定符
Windows.ApplicationModel.Resources.Core.ResourceContext
类封装了可能影响资源选定的资源限定符(qualifiers)。这些资源限定符影响了应用运行时所需资源的选定。查询资源限定符并做出适当匹配优化对于增进用户体验也有帮助。
要获得当前应用的资源限定符,我们需要调用 ResourceContext.GetForCurrentView()
方法获得当前应用视图的资源上下文,再访问其中的 QualifierValues
属性。QualifierValues
属性的类型为 IObservableMap<string,string>
,可通过键名获得对应的限定符值。
以下为 MSDN 文档中列举的可能的资源限定符名称以及对应取值:
资源限定符 | 可能的取值 | 说明 |
---|---|---|
Language | 如 "en-us" | 此限定符名称可以映射到表示语言的字符串值,例如,"en-us" 表示美国英语。 |
Contrast | standard | 此限定符名称可以映射到当前对比度设置值。 |
high | ||
black | ||
white | ||
Scale | 80 | 此限定符名称可以映射到以百分比形式表示显示比例的值。 |
100 | ||
120 | ||
140 | ||
150 | ||
160 | ||
180 | ||
225 | ||
HomeRegion | 如 "021" | 此限定符名称可以映射到表示区域的字符串值,例如,"021" 表示北美。 |
TargetSize | 如 "256" | 此限定符名称可以映射到表示目标大小的字符串值,例如,"256"。 |
LayoutDirection | LTR | 此限定符名称可以映射到当前布局方向的值。 |
RTL | ||
TTBLTR | ||
TTBRTL | ||
Configuration | 此限定符名称可以映射到表示配置的字符串值。 | |
AlternateForm | 此限定符名称可以映射到表示替换窗体的字符串值。 | |
DXFeatureLevel | DX9 | 此限定符名称可以映射到表示 DirectX 功能级别。 |
DX10 | ||
DX11 |
有关 ResourceContext
类的更多用法,可以参阅 MSDN 文档 ResourceContext 类型。
获取当前应用包信息
Windows.ApplicationModel.Package 类型负责提供应用包的信息。要获取当前应用的 Package 对象实例,可以通过 'Package.Current' 属性获取。获取当前应用的包对象之后,我们就可以进一步获得以下信息:
- DisplayName 获取包的显示名称。
- InstalledDate 获取包安装或最近一次更新的时间。
-
InstalledLocation 获取包的安装位置。返回值为
StorageFolder
类型。 - IsBundle 指示该包是否为 Bundle 集合包。
- IsDevelopmentMode 指示该包是否以开发模式安装。
- IsFramework 指示是否有其它包将该包声明为依赖项。
- IsResourcePackage 指示该包是否为资源包。
-
Logo 获取该包 Logo 文件的位置。返回值为
Uri
类型。 - PublisherDisplayName 获取包发布者显示名称。
- InstallDate 获取应用包初次安装的时间。该属性在 Windows 10 上并未实现。过去也仅对 Windows Phone 8 有效。
除以上属性外,Package
类还提供了三个重要的属性:Id 、 Status 以及Dependencies。
Id
属性为 PackageId 类型。该属性提供了当前包 Id 的各种信息,包括:
- Architecture 获取当前包的对应处理器架构。
- FamilyName 获取包的 Family Name。如 "32b04fa8-6b7b-4ed9-8a9b-eade01a24207_hpzxbeh1zj56g "
- FullName 获取包的完整名称。如 "32b04fa8-6b7b-4ed9-8a9b-eade01a242071.0.0.0x86__hpzxbeh1zj56g"
- Name 获取包名。如 "32b04fa8-6b7b-4ed9-8a9b-eade01a24207"
- Publisher 获取包发布者。如 "CN=validvoid"
- PublisherId 获取包发布者 ID。
- ResourceId 获取包的资源 ID。
-
Version 获取包版本。返回值为
PackageVersion
类型,可进一步格式化输出字符串。 - Author 获取包作者。仅限 Windows Phone,在 Windows 10 上无效。
-
ProductId 获取包的
ProductID
属性值。仅限 Windows Phone,在 Windows 10 上无效。
Status
属性为 PackageStatus 类型。该类型提供了一个 VerifyisOK()
方法用于判断当前包的状态是否良好,可以使用。该方法会验证 PackageStatus
中的一系列属性以判断包是否可用。PackageStatus
包含的属性如下:
- DataOffline 指示当前包所用数据是否离线。例如,当应用的数据安装在了 SD 卡等可移动介质上,而该媒体弹出时,数据即为离线状态,则该属性返回 true。
- DependencyIssue 指示包的依赖项状态。当当前包的依赖项之一遭遇异常时,该属性即返回 true。在当前包的全部依赖项解决问题前,当前包将无法使用。
- DeploymentInProgress 指示当前包是否正在被部署过程占用。例如,当包正在更新时,该属性返回 true。
- Disabled 指示当前包是否被禁用。包可以通过PackageManager.SetPackageStatus 进行禁用,或通过PackageManager.ClearPackageStatus 启用。
- LicenseIssue 指示当前包是否有授权问题。例如当授权丢失或过期时,该属性返回 true。所有授权问题解决前,当前包将不可用。
- Modified 指示当前包是否存在内容修改问题。例如,当包丢失了某些文件时,该属性返回 true。
-
NeedsRemediation 指示当前包是否需要进行修正。例如,当
NotAvailable
,LicenseIssue
,Modified
,Tampered
中的一个或多个属性指示出当前包存在异常情况时,该属性即为 true。 -
NotAvailable 指示当前包是否不可用。例如,当
DataOffline
,Disabled
,PackageOffline
中的一个或多个属性指示出当前包存在异常情况时,该属性即为 true。 - PackageOffline 指示当前包是否离线或不能访问。例如,当包文件安装在 SD 卡等可移动介质上,且该介质处于被移除,则该属性为 true。
- Servicing 指示当前包是否处于被占用状态。
- Tampered 指示当前包是否处于感染状态。改属性返回 true 的一种可能原因是第三方反病毒软件将当前包标记为了恶意程序。
Dependencies
属性为 IReadOnlyList<Package>
类型,可用于获取当前包的所有依赖项。注意该属性仅用于获取 Windows Store 应用包的依赖项。要获取一个桌面应用包的依赖项,需使用 Win32 函数 GetPackageInfo。
有关 Package
的具体用法可参见 Github 上的示例代码。
列举 Windows Mobile 设备上已部署的应用包
Windows.Phone.Management.Deployment
命名空间下提供了一系列用于控制应用部署功能的类型,其中 InstallationManager 类型负责应用包的安装管理。我们可以通过其中的 FindPackagesForCurrentPublisher
方法获得当前 Windows Mobile 设备上安装的同一发布者的应用包部署情况。该方法的返回类型为 IEnumerable<Package>
,我们可以进一步检索返回值获取具体某个应用包的详细信息甚至启动这些应用。
值得说明的是,Windows.Phone.Management.Deployment
仅在 Windows Mobile 设备上有效,故在 UWP 应用中使用时,需要配合 AnalyticsInfo.VersionInfo.DeviceFamily
检测当前设备类型,选择是否调用该命名空间下的方法。另外,'InstallationManager' 类中提供的其它方法需要 ID_CAP_OEM_DEPLOYMENT
特别权限才能够正常使用,故一般开发者无法使用。
获取用户数据账户信息
用户数据账户是什么呢?举例说明,如果你用过 Android 系统,那么你在 Android 的系统设置中会看到一项名为“账户”(Accounts)的设置栏目,其中列出了当前系统登录的 Gmail、Outlook、Office、Exchange、微博等各种应用注册的账户。这些账户就是用户数据账户。Windows.ApplicationModel.UserDataAccounts
命名空间定义了用于控制邮件、预约、日历等用户数据账户信息的相关类型和枚举。其中,UserDataAccount 类型表示一个用于存取邮件、联系人、日历等数据的用户数据账户。UserDataAccountManager类型提供了与用户数据账户交互的 API。UserDataAccountStore 代表用户数据账户的储存区。本文主要讲述如何通过 Windows Store App API 获取一些常用的信息,故在此不涉及操作用户数据账户的内容。仅关注如何获得一些数据。
要使用 UserDataAccounts
相关 API,要求应用在清单文件中声明联系人(contacts)、预约(appointments)、邮件(email)等功能中的一个或多个。
假设我们想要列举出当前系统上登录的所有用户数据账户,并输出这些账户的相关信息,首先我们需要通过 UserDataAccountManager.RequestStoreAsync
方法向系统请求用户数据账户的储存区。该方法接受一个 UserDataAccountStoreAccessType 枚举类型的参数。该参数用于指定要求的用户数据账户存储区的访问类型。UserDataAccountStoreAccessType
枚举包含两个成员:
-
AllAccountsReadOnly
对应用以及系统的用户数据账户进行只读访问 -
AppAccountsReadWrite
对当前应用的用户数据储存区进行读/写访问
由枚举可知,我们虽然可以检索当前应用自身以外的用户数据账户,但对于自身以外的用户数据账户并没有写权限。
这里我们选择第一种访问类型,使用以下代码请求用户数据账户储存区:
UserDataAccountStore userDataAccountStore = await UserDataAccountManager.RequestStoreAsync(UserDataAccountStoreAccessType.AllAccountsReadOnly);
获取到的用户数据账户储存区实例为 UserDataAccountStore
类型,该类型包含三个方法:
- CreateAccountAsync 创建一个用户数据账户。
- FindAccountsAsync 根据指定的访问类型返回用户数据账户储存区中的账户集合。
- GetAccountAsync 获取指定用户数据账户。
这里我们调用 FindAccountsAsync
即可获得所有用户数据账户,并进行下一步操作。具体演示可参见 Github 上的示例代码。
获取系统用户信息
在 Windows 8 应用中,我们使用 Windows.System.UserProfile
命名空间中的UserInformation 访问系统登录的用户账户信息。而在 Windows 10 以及以后版本的 Windows 中,UserInformation
不再被支持。因为在 Windows 10 中,除非用户授权,应用是不能获取用户信息的。而 Windows 8 应用则是默认得到授权的。并且,旧的 Windows 8 应用运行于 Windows 10 时也无法正常获取用户信息。
在 Windows 10 上我们需要使用新的 API 提供的Windows.System.User 类型获取用户信息。注意使用该 API 需要应用在清单文件中配置“用户账户信息”(User Account Information) 功能。
User
类提供了三个静态方法及其重载:
- CreateWatcher 创建一个监视器用于在列举用户账户或用户账户发生变更时出发有关事件。
- FindAllAsync 查找所有用户账户。
- FindAllAsync(UserType) 查找指定类型的用户账户。
- FindAllAsync(UserType,UserAuthenticationStatus) 查找指定类型和验证状态的用户账户。
- GetFromId 根据 ID 获取指定用户账户实例。
我们可以通过 FindAllAsync
或 GetFromId
方法获取用户账户实例,获取用户后,可以通过调用 GetPropertyAsync 方法取得该用户的属性信息。GetPropertyAsync
方法接受一个 string 类型的参数,具体传入内容可以通过 KnownUserProperties 类中定义的属性获取。 KnownUserProperties
类中定义了已知可用的用户账户属性键名。例如,我们想要获取账户显示名称时,可以采用如下方法:
string displayName = await user.GetPropertyAsync(KnownUserProperties.DisplayName);
User
类还包含以下三个属性成员:
- AuthenticationStatus 获取用户账户的验证状态。返回值为枚举类型UserAuthenticationStatus。
- NonRoamableId 获取用户的非漫游 ID。
- Type 获取用户的用户账户类型。返回值为枚举类型 UserType。
配合使用 UserDataAccount 和 User 两个 API 可以使应用更好地实现唯一用户识别、用户账户体系、自定义授权等功能特性。
更多内容请参阅本文后续内容更新。
第二篇:UWP 应用获取各类系统、用户信息 (2) - 商店授权信息、零售演示模式信息、广告 ID、EAS 设备信息、硬件识别信息、移动网络信息