[UWP] 為WinRT組件創建Nuget包


Nuget 是 dotnet 開發中必不可少的包管理工具,但不僅僅局限於 dotnet 項目,在 VS 中使用 C++ 開發的時候,也可以使用 Nuget 來引用第三方組件。同樣也可以用 Nuget 把 native 的一些組件打包,提供給自己或者別人使用。

這片博文記錄一下如何把 WinRT 組件打包成 nuget 包,供 UWP 項目使用。

之前提供給合作伙伴我們的 WinRT 組件時,是直接把 .winmd文件 和 .dll文件發給他們,其中 .winmd 提供聲明,.dll 提供具體的實現。然后使用者就可以手動引用和復制這兩個文件到項目里面使用。

但通過 Nuget 包的形式,一方面便於管理和發布,另一方面可以很好的做到版本控制。

實戰如下:

准備原材料

Demo.winmd

主要包含命名空間,類之類的聲明,因為本質上使用的是 COM 技術,所以即使只添加對 .winmd 的引用,UWP 項目依舊可以成功編譯。

Demo.dll

包含對應 .winmd 的具體 COM 實現。

Nuget.exe

用來打包 nuget 包,可以從 nuget 官網下載(https://www.nuget.org/downloads

創建 Nuget 包聲明文件(.nuspec)

可以使用如下命令來生成一個名為 demo.nuspec 的模板文件

nuget spec demo

在此文件中,需要加入對 Demo.winmd 和 Demo.dll 文件的引用,修改完成后如下

<?xml version="1.0"?>
<package >
    <metadata>
        <id>com.cq.nugetdemo</id>
        <version>1.0.0.0</version>
        <title>Nuget Demo</title>
        <authors>cq</authors>
        <owners>cq</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Just a test</description>
        <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
        <copyright>Copyright 2019</copyright>
        <tags>demo</tags>
    </metadata>
    <files>
        <!-- WinMd and IntelliSense files -->
        <file src=".\Nuget.winmd" target="lib\uap10.0"/>
        
        <!-- DLLs and resources -->
        <file src=".\Nuget.dll" target="runtimes\win10-x64\native"/>
        
        <!-- .targets -->
        <file src="com.cq.nugetdemo.targets" target="build\native"/>
    </files>
</package>

metadata 節點提供一些必要的 nuget 包信息聲明,最重要的是 id,這個要保證唯一性。

引用文件的位置是以 demo.nuspec 文件的位置為基准,可以使用相對路徑。

需要將 nuget.winmd 文件放入 lib 文件夾下的 uap10.0 目錄,其中 lib 文件夾會在最終生成的 nuget 包中創建,uap10.0 代表此文件只會被 UWP 應用引用。

需要將 demo.dll 文件放入 runtimes 文件夾下,同樣這個文件夾我們不需要手動創建,它會在最終生成的 nuget 包中出現。win10-x64 代表該 dll 為 x64 cpu 架構,win10-x86 就代表32位,native 則表示此 dll的類型。

com.cq.nugetdemo.targets 文件和 demo.nuspec 文件在同一目錄,它主要是為了讓 C++ 的 UWP 項目也能正確添加對 nuget 包中 dll 和 winmd 文件的引用,在 C# 項目里面IDE會幫我們添加。 該文件如下:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <NugetDemo-Platform Condition="'$(Platform)' == 'Win32'">x86</NugetDemo-Platform>
        <NugetDemo-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</NugetDemo-Platform>
    </PropertyGroup>
    <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'UAP'">
        <Reference Include="$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Nuget.winmd">
            <Implementation>Demo.dll</Implementation>
        </Reference>
        <ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(NugetDemo-Platform)\native\Demo.dll" />
    </ItemGroup>
</Project>

雖然 C# 的 UWP 項目不需要 .targets 文件,但是為了讓 IDE 能正確添加對 DLL 文件的引用,我們需要保持 dll 和 winmd 文件同名,否則在運行時會拋出異常。在編譯時,會有如下警告:

warning APPX1707: No implementation file was provided for the .winmd file 'C:\Users\...\.nuget\packages\com.cq.nugetdemo\1.0.0.3\lib\uap10.0\demo.winmd'. To generate registration information in the app manifest, specify the 'Implementation' metadata on the .winmd reference item in the project file.

創建 nuget 包(.nupkg)

nuget.exe pack NugetDemo.nuspec -Version 1.0.0.3

在創建的時候,可以指定版本號,這方便我們用自動化腳本來生成 nuget 包。執行此命令后,在demo.nuspec 同級目錄下會生成對應的 .nupkg。

使用 nuget 包

正常使用 nuget 包時,可以通過 VS 里的 nuget 包管理器去安裝。但是如果我們的 nuget 包只想本地使用,那我們可以給 nuget 包管理器添加一個本地的包源,

在 .sln 同級目錄,創建一個 Nuget.config 文件,然后可以在里面配置本地的 nuget source

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <add key="MyLocalSource" value=".\NugetPackage" />
    </packageSources>
</configuration>

其中 MyLocalSource 是包源的名稱,.\NugetPackage 是包源的路徑,也是相對路徑

現在就可以在包管理器中選擇對應的本地源,然后安裝生成的 .nupkg

參考

我主要參考了微軟的官方文檔:

https://docs.microsoft.com/en-us/nuget/guides/create-uwp-packages

微軟文檔會更加全面一些,而這篇博客主要是我的具體實踐,對比該文檔去掉了一些 暫時沒發現有什么用 的步驟,添加了一些值得注意的點。

微軟文檔里提到的如下兩點,在這個 demo 里沒有用到:

Package Resource Index (PRI) file

微軟文檔

Every app package should contain a binary index of the resources in the app. This index is created at build time and it is contained in one or more Package Resource Index (PRI) files.

  • A PRI file contains actual string resources, and an indexed set of file paths that refer to various files in the package.
  • A package typically contains a single PRI file per language, named resources.pri.
  • The resources.pri file at the root of each package is automatically loaded when the ResourceManager is instantiated.
  • PRI files can be created and dumped with the tool MakePRI.exe.
  • For typical app development you won't need MakePRI.exe because it's already integrated into the Visual Studio compile workflow. And Visual Studio supports editing PRI files in a dedicated UI. However, your localizers and the tools they use might rely upon MakePRI.exe.
  • Each PRI file contains a named collection of resources, referred to as a resource map. When a PRI file from a package is loaded, the resource map name is verified to match the package identity name.
  • PRI files contain only data, so they don't use the portable executable (PE) format. They are specifically designed to be data-only as the resource format for Windows. They replace resources contained within DLLs in the Win32 app model.
  • The size limit on a PRI file is 64 kilobytes.

簡而言之,PRI 文件相當於傳統 Win32 開發中的 資源 DLL 文件。

XML documentation (Demo.xml)

在 IDE 的 C++ output file 屬性頁面,可以打開如下選項

Generate XML Documentation files (/doc)

打開之后,就會生成和我們的 native dll 同名的 .xml 文件,大致如下:

<?xml version="1.0"?>
<doc>
    <assembly>
        <name>ClassLibrary</name>
    </assembly>
    <members>
        <member name="T:ClassLibrary.Demo">
            <summary>
            A demo how to use documentation.
            </summary>
        </member>
        <member name="M:ClassLibrary.Demo.GetDate">
            <summary>
            Get date of now.
            </summary>
            <returns>a date time struct</returns>
        </member>
    </members>
</doc>

當把這個 .xml 和 .dll 同事分發給使用者時,使用者在 VS IDE 里面就能獲得對代碼注釋的 智能感知 能力。當然這要求我們在提供編寫 .dll 的源代碼的時候,提供規定格式的良好的注釋。

注釋格式可以參考如下:

C++ https://docs.microsoft.com/en-us/cpp/build/reference/xml-documentation-visual-cpp?view=vs-2019

Dotnet(C#) https://docs.microsoft.com/en-us/dotnet/csharp/codedoc

One more thing

事實上在 demo.dll 是一個 COM 服務器,使用前需要先注冊,在 UWP 項目里如何注冊這個 COM 服務器呢?

當我們添加對 .winmd 和 .dll 的引用后,在 UWP 的 AppMenifest 文件里面會自動添加如下節點:

<Package>
    <Extensions>
        <Extension Category="windows.activatableClass.inProcessServer">
            <InProcessServer>
                <Path>Nuget.dll</Path>
                <ActivatableClass ActivatableClassId="Nuget.Class" ThreadingModel="both" />
            </InProcessServer>
        </Extension>
    </Extensions>
</Package>

Github

Demo 下載

歡迎關注我的微信公眾號
CQInfo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM