草庐IT

【教程】开发Unity PackageManager 插件包

雨落随风 2023-09-30 原文

在本文笔者将带大家走完 UPM(Unity PackageManager) 插件包的开发流程,在本文你将学会 UPM 插件包的正确构建与调试流程、GitHub发布、插件更新与下载使用。从此Github 将是你的超级在线插件包~

友情提示:建议从下往上翻, 或者上半部分快速翻阅,毕竟上面的内容较为过时了~

Tips :Unity 2018.3 及之后版本, Unity Package Manager (UPM) 已经支持 Git 了.
https://forum.unity.com/threads/git-support-on-package-manager.573673/
这个更新使得我们能够快速的安装那些托管在诸如 GitHub,Gitlab,Gitblit 等代码托管服务上的插件包。

这样,只要给个git链接就能安装插件/更新插件了,并且这个工作流可以让插件的开发和维护与用户工程的开发文件完全隔离,做到不污染用户工程又能将插件用于实际开发中,UPM 提供的这种便利在不远的将来将是 Unity developer 的一场狂欢,并且这一天并不遥远。

言归正传,下面我们创建一个 UPM 插件包吧~
本教程中,我们将开发一个名为 “RotateMe” 的插件包,它包含一些用于驱动游戏对象旋转的组件。

本文不涉及远程仓库的创建以及Git 安装

简要步骤

  • 像往常那样开发。
  • 添加 asmdef 文件
  • 添加 package.json 和必要文档
  • 执行"git subtree split" 和tag命令

分支策略

在本教程,我们使用 2 个分支来开发这个插件包。看个人喜好,如有必要可以增加分支(比如:develop 分支)。

  • master 分支: 插件包开发环境,也就是一个正常的Unity工程。
  • upm 分支: 插件包发布的分支,也是供 UPM 读取和安装的分支。

请注意,不能直接往 upm 分支提交,也不要使用 git branch upm 的方式手动创建此分支。

目录结构

UPM包的公共目录结构如下:


将上述插件包资源使用一个根节点统筹之,这个文件夹建议以插件名来命名,如下:


怎么样,是不是就像往常开发那样的流程呢?
开发插件包的过程无不透露着熟悉的味道哈。

开发插件包

OK,现在我们在 "master" 分支中开发并调试我们的插件。
首先撰写一个用于驱动物体旋转的示例代码并放在这个文件夹下:
Assets/RotateMe/Scripts/RotateMe.cs
示例代码如下:

using UnityEngine;
public class RotateMe : MonoBehaviour
{
   public float angularVelocity = 10;
   void Update ()
   {
       var rot = Quaternion.AngleAxis (angularVelocity * Time.deltaTime, Vector3.up);
       transform.localRotation = rot * transform.localRotation;
   }
} 

当然,别忘了添加一个 Demo 场景。
要知道 Demo 场景可是一个可交互的手册呢,有了它用户就可以轻松的掌握怎么使用插件咯!


添加 asmdef 文件

如果要开发包含脚本的插件包,这边建议您添加一个asmdef文件的呢,亲~
https://docs.unity3d.com/2018.3/Documentation/Manual/ScriptCompilationAssemblyDefinitionFiles.html

这个 asmdef 文件能将它所在的文件夹及其子文件夹的脚本打到一个独立的程序集中,表象上就是这些个脚本打到了独立的 dll 中了。

简单的说下 asmdef 文件的优势.

  • 更短的编译时间
  • 把"internal"访问修饰符用到了极致(要知道以往的源代码插件,因为与用户脚本编译在了同一个程序集,所以它的 Internal 修饰符并没起到应有的作用,暴露了太多,就是一个掩耳盗铃的迪米特法则罢)
  • 允许使用 unsafe code
  • .dll 文件可以指定特定的程序集引用。

如下图,如果你勾选了 "Test Assembly",程序集只在编辑器下生效而不会出现在打包的程序中。

搬运的原教程中没有涉及到到 AssemblyDefinition 的相互引用关系,故而笔者在这里补充下。

目录管理

  1. 建议使用Editor 文件夹汇总所有的编辑器脚本,而将运行时的脚本使用 Runtime 文件夹汇总,参考 TextMeshPro 插件包的结构:


  2. 在Editor 和 Runtime 文件夹下各自创建一个 AssemblyDefinition 。
  3. Editor 文件夹下的 AssemblyDefinition 中 Platform 只能选择 Editor,并且 Reference 必须添加上 Runtime 中的那个 AssemblyDefiniion ,依旧参考 TextMeshPro :


添加文档

UPM 插件包需要一个 package.json 包体描述文件,保存在如下路径:"Assets/RotateMe/package.json".(插件根节点)

{
"name": "com.coffee.rotate-me",
"displayName": "Rotate Me",
"description": "Rotate the object!",
"version": "1.0.0",
"unity": "2018.3",
"license": "MIT",
"dependencies": {
 }
}

更多详情请见: https://docs.npmjs.com/files/package.json.

README.md, CHANGELOG.md, LICENSE.md 都可选但可以给用户带来更多信息。
将这些文档放在"Assets/RotateMe" 文件夹.
当然也可以放在"Assets/RotateMe/Document~",需要注意的是文件夹名称以~结尾不会显示在Project窗口

完成开发

完成了上面的几步,我们的插件包就算是完成啦。
最终 "master" 分组看起来就像这样:


(如果你暂时不考虑 UPM ,可将这个文件夹导出成 unitypackage 发布)

发布UPM包

如果想要发布 UPM 包,我们必须通过如下git 命令把插件包所在的文件夹创建为 subtree。

git subtree split --prefix=Assets/RotateMe --branch upm

这个命令将 "Assets/RotateMe" 目录放到“ upm” 分支。
通过这一步其他目录及文件不会出现在 upm 分支中。
接下来,为这个分支添加一个 tag 并推到远端。
推荐使用 semver作为 tag 的命名规则。

git tag 1.0.0 upm
git push origin upm --tags

大功告成!
这样,我们的 “RotateMe” UPM包就发布好了!
最终,分支图像这样子:


注意橙色那一行的信息

安装 UPM 包

现在,我们试试把 RotateMe 使用 UPM 安装到其他工程中。

找到 "Packages/manifest.json" 插入如下一行:

{
 "dependencies": {
     "com.coffee.rotate-me": "https://github.com/mob-sakai/RotateMe.git#1.0.0",
     ...
 },
}

回到编辑器 Unity 就能自动加载咱们的插件啦,就像这样:


或者使用 UpmGitExtension来安装。

版本更新

  • 在 "master" 分支开发和调试然后在 package.json 更新版本信息
  • 执行 "git subtree split"
  • 添加 tag 然后 push。

如此简单~

你也可以把已经存在的仓库使用同样的操作将其适配 UPM 。

本教程测试用的仓库如下,不受限使用。
https://github.com/mob-sakai/RotateMe

总结

仅需几步,就能将 git 仓库直接变得支持 UPM。
如果 Github 上的Unity 工程都支持 UPM 那会有多棒!?
现在,就把你工程的 UPM 支持搞起来吧~

2020.3.4补充:

  • 使用 file 协议,形如: "com.bshsf.commoncode":"file:../../Common",可以将UnityPackage包放在本地,这样多个工程就可以使用一个公共代码,也方便同步修改,比如在socket通信的客户端与服务端使用这种方式同步消息数据结- 来自笔者的示例
    • file 协议中,默认的根节点文件夹是工程目录下与Assets 文件夹同级的 Packages 文件夹,也就是说如果你的Pacakge路径写成 file:Common ,那你的插件包请放在Packages文件夹下。
    • 一般来说,我们会把插件包放在工程之外,方便其他工程引用,可以使用2个"../" 往上走2个目录层级,比如"com.bshsf.commoncode":"file:../../Common" 表示这个插件包是跟工程根目录同级的了。
  • 如果你安装了git 并设置了git的 Path环境变量,但是Unity还是报相关错误,这可能是因为你的环境变量路径没有指定正确,64位Windows 10 我给的参考路径是:"C:\Program Files\Git\mingw64\libexec\git-core" ,非默认安装路径的自行合理拼接 。

2020年10月26日 更新

在新版的Unity中(笔者使用的是Unity 2019.4.12),PackageManager 支持直接输入 git 链接了,这样带来两个好处:

  1. 不需要手动改 package.json
  2. 依旧支持打tag 做插件包的更新哦!


2021年2月28日 更新

随着 UPM 的日趋完善,现在这个工具已经支持配置自定义 Scope Registry 了,如此一来便解决了包的依赖问题了。
安装目标插件时,UPM 会自动根据你声明的依赖包 id 从你配置的 Scope Registry 服务器上拉取依赖的包。
目前,OpenUPM 作为野生 Unity 插件包的集聚地已然是独具规模了,通过它你可以公开发布你的插件,同时还可以轻轻松松(写上依赖包ID就行)随意引用和依赖这个Registry 中的其他开发者的包。
如果你正在找这方面的教程,你可以看看这个良心之作:使用OpenUPM发布自己的Unity项目-有木酱的小屋
当然,你也可以搭建 Scope Registry 私服,MixedRealityToolkit-Unity就是微软自己的Scope Registry,我相信你也可以搭建成功的(PS:OpenUPM 开源哦~)。

UPM Scope Registry 在哪儿设置:


UPM上找到齿轮点击进去就到这个界面了

2021年4月2日更新

在有些没有外网的公司,UPM 会报错:Cannot perform upm operation:connect ETIMEDOUT 35.238.138:443 [NotFound] 以及一个 Error Searching for packages报错,如图示。


可以参考这个连接尝试去解决 : 自己搭建Unity Package Server - 知乎

2021年8月27日更新

有朋友问我提交新版本可不可以不打 tag 值,开发阶段频繁更新 tag 对同事不友好。
回答是可以不打,因为打 Tag 主要只是告诉 git 插件目录在哪儿,其次才是附加值:标记插件版本、触发 UPM 加载

其实,笔者知道的,要访问插件目录,不限于这种https://github.com/mob-sakai/RotateMe.git#1.0.0带 Tag 形式的 git 链。

还有以下 3 种形式:

  • 使用形如https://github.com/mob-sakai/RotateMe.git#upm 通过直接指定分支名称。
  • 使用形如https://github.com/wlgys8/LitTask.git不带 tag 的 git 链,其特点是插件目录本身即为 git 仓库。
  • 使用形如https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask 的带 QuaryString 参数的 git 链 (需要新版本 Unity 以支持对 querystring 参数解析)

↑ 鉴于笔者并非 git 精通,故而只能列举四种方式,毋需置疑,这些肯定也只是冰山一角。如果笔者见到了新的方式亦会慢慢补全↑

关于终端用户不友好,遵循这种工作流就不会产生困惑了:
对于开发者,累计功能点阶段性推版本
对于终端用户,小迭代自发更新,大迭代提醒强制更新。

最后

  • 还是建议大家使用 Tag ,因为毕竟相较于另外2种形式,它能够正常触发 UPM 更新
  • 其他 2 种形式需要自己找方法触发更新(比如一顿删除再粘贴 git 链)。
  • 除第三种方式,另外 3 种方式是支持一个仓库存多个插件的,自己扩展一下也能实现插件之间的引用。

2022年1月22日更新

  • 上一次更新说到的 UPM 支持 4 种协议,现在可以更新一下了,下面是更完善的支持的协议说明:
    官方中文手册 :https://docs.unity3d.com/cn/current/Manual/upm-git.html

  • 另外,Unity Registry 托管的插件包支持直接将形如 com.unity.learn.iet-framework@2.0.0 这种 【包ID+版本】链接写入到UPM git url 中获取插件包,下面是参考链接以及其上下文截图:
    Tutorial Authoring Tools | 1.0.0

2022年5月3日更新:

Unity 已经开发出了 UPM Package 开发工具,只需要简单一步就能够创建 Package 大致框架,剩下的仅仅是代码的搬运了。
目前,这个 UPM 开发工具还是预览阶段,有可能在 UPM 的 Unity Registry 中还看不到。
点击 + 号 ? 点击“Add Package from git” ? 粘贴上 com.unity.upm.develop ? 点击 “Add” 即可安装。

安装

使用见下图,只需要点击图示菜单即可构建一个 package 环境
使用

预设 Package 开发环境如下,可见留给用户的工作量不多了:代码+Readme 补全

同时 UPM 包开发工具提供了一套校验性质的功能点入口,如图示,依次是:单例测试、包有效性校验(检测包配置是否合理)、真机导入测试、包的发布。

2022年6月14日更新

还是要说一下,除了 .asmdef 文件,Unity 还给了一个 .asmref 文件,全称为: Assembly Definition Reference,这个文件能够解决咱们在架构插件时 .asmdef 不能跨文件夹的痛点。
有了 .asmref 文件,可以将各处的文件夹的源文件打进一个程序集中,很多时候避免了目录结构的非必要重构。
使用也是很方便,只要你对着文件夹点右键,选中 Assembly Definition Reference ,接下来的操作便能够心领神会了。

2022年10月13日更新

插件中部分代码想要选择性的参与编译,可以通过在 Assembly Definition File 中 的 Version Define 自定义宏,并选择宏开启的条件,条件一般为:

  1. 在特定的程序集存在的情况下启用宏(图中 Resource 展开选择即可)
  2. 在特定版本的程序集存在的情况下启用宏,如对版本不做限制,输入0.0.0 或 “0”或者留空即可

注意:

  • 笔者选择 com.unity.modules.ui 仅作演示,宏:UNITY_UGUI_ENABLED 也是随手写的,用户需自行修改为存在性存疑的程序集
  • 当我们按上图所示修改此 asmdef 文件后,使用 UNITY_UGUI_ENABLED 即可约定哪些代码是准备选择性编译的啦。
  • 如果确信程序集存在且版本正确,但是宏未启用,请为插件重新生成vs项目,如下图所示(再不行重启 Unit y 和 IDE(如 VS),哈哈哈)
高亮部分保持勾选

如果想要自己整理的 upm 插件导入时自动安装依赖(的 upm),只需要在你的插件的 package.json 的 dependencied 成员中加入依赖包的 id 和 版本号即可,如下图所示。


Tips:

  • 如果版本不想写死,那可以用 default 代替具体的版本号试试吧
  • git url 的依赖应该暂时不支持,大家可以试试,Unity 不停的更新,指不定有惊喜呢?

扩展阅读

本文部分内容由笔者搬运并翻译自 Tutorial: How to develop a package for UnityPackageManager

有关【教程】开发Unity PackageManager 插件包的更多相关文章

  1. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  2. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  3. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  4. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  5. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  6. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  7. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

随机推荐