这里的自定义package指带有特定功能的一些文件做成在别的工程通过package manager加载的包。

功能插件做成自定义packge的特点在于让插件的开发和维护与用户工程的开发文件完全隔离,用户工程不能更改插件内容但是能将插件用于实际开发中。

实际云端给的单个项目大小一般最大不可能有超过2G,coding的最大,码云的第二,github第三,这种情况下,package manager的方式是比较适合的。

package可以放置任意格式的文件,在package中的prefab和scene等所有文件不能被更改,只能拖拽复制到当前场景,或者拖拽到Assets文件夹中,拖拽到Assets中之后更改才能被保存。

而且预制体拖拽出来也会出现丢失脚本。

但是实际操作时候发现自定义package里面的场景实际上引用之后是使用不了的, 即使将场景拖拽到asset文件夹, 上面挂载的来自package的脚本会识别不了。而且即使package里面含有类似Tool这类在顶部的编辑界面代码 引用后的工程也不会出现。

在这里插入图片描述

文章的操作是在Mac系统下进行的,Windows操作步骤大体相同,细节有点差别

创建自定义package

unity对自定义package的文件夹结构有一定的要求,开发者需要遵循这些要求制作。详细参考Package layout
image.png

主要如下:

  • package.json:package的清单文件,是必须的。以键值对的形式定义了一系列详细信息。其中name和version字段是必须的,name字段定义了唯一标识,字段里面的值不能带有大写英文字母,name字段也不需要和playersettings里面的package name相同。version定义了当前的版本,开发者习惯一次更新package将版本号会加一次。其他的字段和详细写法参考 Package manifest

  • README.md 以md的形式记录的使用手册说明文档

  • CHANGELOG.md package的版本更新记录,记录每次更新的内容

  • Editor文件夹 所有只在编辑器下运行的脚本放在这个文件夹下,习惯放一个asmdef文件将这个文件夹下面的脚本文件打入一个程序集。asmdef文件详细参考Assembly definition and packages文件的命名不规范不会造成什么问题,也不需要和playersettings里面的package name相同,只是推荐命名按照上述链接进行。
    asmdef 文件能将它所在的文件夹及其子文件夹的脚本打到一个独立的程序集中,表象上就是这些个脚本打到了独立的 dll 中了。简单的说下 asmdef 文件的优势:

    • 更短的编译时间
    • 把"internal"访问修饰符用到了极致(要知道以往的源代码插件,因为与用户脚本编译在了同一个程序集,所以它的 Internal 修饰符并没起到应有的作用,暴露了太多,就是一个掩耳盗铃的迪米特法则罢)
    • 允许使用 unsafe code
    • .dll 文件可以指定特定的程序集引用。
  • Runtime文件夹 在unity打出的程序中运行的脚本放在这个文件夹下,习惯放一个asmdef文件将这个文件夹下面的脚本文件打入一个程序集。实际使用发现并不要求Runtime文件夹只放在根文件夹下

其他的prefab和scene等文件放置文件夹不做要求。

示例创建自定义Package时,将工程Assets的某个文件夹下的文件用于作为Package使用而不是整个Assets文件夹,所以里面的布局需要符合规范。这里称Assets称为主工程。最后的文件结构如下所示,DebugUI下的所有文件是package的内容。custom package格式如下所示:

image.png
之所以将要更新到package的内容放到一个专门的文件夹是有原因的:package内容的产出有时需要长期依赖一定的工具,这些工具放到更新包显然不合适,而且如果两个package需要相同的工具,这些工具都放到更新包的话,那么如果有个工程刚好导入了这两个package,那么会导致冲突问题。

示例的package.json结构如下:

{
  "name": "com.iyourcar.debugui",
  "displayName": "Iyourcar DebugUI",
  "description": "DebugUI",
  "version": "1.0.5",
  "unity": "2019.4",
  "license": "MIT",
  "author": "Iyourcar",
  "keywords": [
    "DebugUI"
  ]
}


引入自定义package

常用的有引入本地unity package和引入git 的package, 后面还要介绍通过npm引入package。

本地引入

本地引入通过unity引擎上的packager manager面板添加(Window->Package Manager->面板左上角加号->选择from disk,然后选择对应工程的package.json文件即可,在引入的时候可能会遇到错误集合第1条的问题。

image.png

git引入

示例使用2个git分支来开发这个插件包,实际情况数量因人而异。

  • main分支: 插件包开发环境,也就是一个正常的Unity工程,更新工程只通过这个分支,这里通过他上传package所在的整个unity工程。

  • upm分支: 插件包拉取的分支,只提供upm的拉取和安装,不使用git branch upm的方式创建此分支,因为这里的upm分支只能拉取DebugUI下的内容,使用git branch upm创建的分支会将整个上传的工程拉下。

第一次布置并引入

布置好package并上传到git
  1. 在github登陆后点击头像选择Repository(仓库),进入仓库面板,点击New(创建),填好之后创建仓库。

image.png

  1. 打开终端或命令行窗口 输入cd 然后拖拽项目Assets文件夹上一级文件夹 到窗口并输入Enter 然后输入 git add .gitignore创建gitignore文件或者复制其他unity项目的.gitignore文件到项目Assets文件夹上一级文件夹的位置。.gitignore文件用于忽略提交时候一些特定后缀到文件

  2. 依次输入如下每一行,输完一行按一次键盘中间的enter:

git init  // 在当前选择文件夹下初始化生成git本地配置文件
git add . // 添加当前文件夹下的所有后缀在gitignore之外的文件到暂存区 如果添加失败可以先关闭unity再添加,或者使用IDE软件如VisualStudio或者Rider的Git功能进行添加
git commit -m "提交描述" // 将暂存区修改内容提交至本地仓库中 
git branch -M main //创建名为main的分支
git remote add origin https://github.com/WenQinNing/TempTest.git
// 将本地仓库关联到远程仓库 这里的远程仓库是主仓库 这里的git地址是项目的http地址不是ssh地址
git push -u origin main -- 创建远程main分支 同时将本地仓库推送到远程仓库的main分支 加了origin表示远程的意思             

因为是http的git地址,第一次push操作需要输入用户名和密码
Username for ‘https://github.com’: 输入的是github上的邮箱账号, 不是github中设置的username!
Password for ‘https://你的github邮箱@github.com’: 输入github的登录密码,点击enter键即可。
其他的git网站也是账号密码这个思路。
执行add命令的时候,可能有些文件会添加失败并停止添加,重新多执行几次add命令即可。

  1. 因为Unity Package Manager 通过git访问package manager的时候需要直接找到package.json, 这要求在上传之后需要将前面声明的A文件夹,作为一个子树分支仓库节点。然后将这个git地址输入。
    所以输入了上述命令后,紧接着输入
git subtree split --prefix=Assets/DebugUI --branch upm //生成upm分支 将Assets/DebugUI目录放到upm分支,要注意如果Assets下的某个文件夹名字带有空格,则执行这句命令会出现问题,我的做法是将名字改了之后重新执行add commit 和push
git tag 1.0.0 upm //给upm分支打标签为1.0.0
git push origin upm --tags //将带tag的upm推送上远程服务器

操作过程如下图所示:
image.png

这时刷新git网站的仓库项目面板,查看分支部分页面可以看到多了个upm分支,这里的upm分支是用于更新unity package的。

引入到git

在上述方式创建了git子树(subtree)之后,
在仓库面板选择对应的项目,然后点击code按钮选择https下载,注意这时github给出的git的https地址是和主仓库地址的git是一样的,都是主工程的git地址,将它复制出来,右键unity编辑器里面的Project面板下的package文件夹选择reveal in finder(Mac系统)或者open in explorer(win系统),在文件浏览器找到manifest文件,在文件的“ dependencies”的值下添加字段,如下所示:

{
  "dependencies": {
    "com.xx.xx": "url"
  }
}

其中"com.xx.xx"和package.json里面的name字段相同,"url"字段是刚刚复制的git地址,后面加上路径,路径直到package.json所在的文件夹,如下所示:

{
  "dependencies": {
    "com.unity.example": "https://github.com/WenQinNing/TestDebugUI.git?path=/Assets/DebugUI"
  }
}

package做了更新重新上传git之后 这种写法要重新引入可以将这句话删除然后回到unity然后再粘贴回去再回到unity。

也可以加上前面用tag标签命令时候的版本号,如下所示,两种做法的作用是一样的都可以找到子树分支的git所在的目录。注意这里的版本号是和之前git命令行上传时候的tag一致,不是在package.json里面的版本号。

{
  "dependencies": {
    "com.unity.example": "https://github.com/WenQinNing/TestDebugUI.git#1.0.0"
  }
}

推荐使用版本号的方式,能知道引用的是package的第几个版本,并且更新也是改版本号即可。
建议在git引入之前直接引入看看有什么问题,直接引用没问题的情况下,git引入出的问题一般是git上的操作上的问题。还有注意双引号和逗号需要是英文的

后续更改上传package和更新拉取package

更改上传package

后续做了更改之后,建议提升package.json里面version字段代表的版本号来清楚版本更新的次数,然后执行以下命令:

git add . // 添加当前文件夹下的所有后缀在gitignore之外的文件到缓存区
git commit -m "提交描述" // 将暂存区修改内容提交至本地仓库中
git push -u origin main -- 将本地仓库推送到远程仓库到main分支 加了origin表示远程的意思 

但是这时子树分支还没被刷新到,只有主仓库被更新到了。再次依次执行下述命令:

git subtree split --prefix=Assets/DebugUI --branch upm // 再次将main分支的Assets/DebugUI文件夹下的内容覆盖upm分支的所有内容

git tag 1.0.2 upm  //给upm分支打标签 标签名为1.0.2  
                              
git push origin upm --tags  //将带有tags的upm分支推送到远程服务器,覆盖oring upm分支 
更新拉取package

找到工程的Packages文件夹下的manifest文件,更改相应字段的url后面的版本号为git上面打标签的版本号。

"com.iyourcar.debugui": "https://github.com/WenQinNing/TestDebugUI.git#1.0.2",

在这个过程可能会遇到一些冲突问题,参考报错集合5

npm部署和引入

环境的安装

  1. 官网下载nodejs并安装,mac用户应该不用管这一条,苹果机mac装系统时候自动会安装

  2. 安装完之后Mac系统下打开终端,windows系统下打开cmd,Mac系统在窗口下输入sudo su将身份变成管理员。

  3. 输入npm install -g verdaccio安装verdaccio

  4. 终端输入verdaccio,启动verdaccio,上述操作过程如下图所示

image.png

部署

  1. 创建sh文件并让它与Assets文件夹同级,如下图所示。
    image.png
    .sh文件是脚本文件,一般都是bash脚本。里面添加如下内容:
npmServer="http://192.168.6.59:4873" //声明值为 http://192.168.6.59:4873 字符串的变量npmServer, 这个值是公司内部搭建的npm私有服务器的ip地址

loggedUser=$(npm whoami --registry $npmServer) //将npm的当前登录的用户名赋值到loggedUser变量,npm whoami --registry $npmServer原意是将npmServer的当前用户名打印到控制台,$()这个bash语法将一些括号内执行的操作结果获得,然后用其外部的命令对这些结果进行操作,这里就是将输出的结果用等号赋值给loggedUser变量

if [ -z "$loggedUser" ];then //if语句开始 意思是如果loggedUser这个变量是长度为0的字符串则为true
  npm adduser --registry $npmServer // 创建或者验证当前npmServer所指地址的默认注册用户 
fi //if语句结束
npm publish Assets/com.iyourcar.debugui --registry $npmServer
// 在npmServer指向的网址发布Assets/com.iyourcar.debugui路径指定的包 

上面是一段是Bash程序,Bash语言里面可以嵌入命令行运行指令,这里嵌入了npm的运行指令,不懂Bash语法可以先看看Bash基本语法,npm的命令行运行指令参考:CLI documentation,这里可能会造成报错集合6的情况。

  1. 输入cd 并拖拽Assets上一层文件到 命令行窗口 按下Enter 让命令行进入到Assets上一层的文件夹,然后输入ls,查看当前文件夹下的文件列表,然后输入sh publish.sh 运行刚刚创建的sh文件, 操作结果如下图所示:

image.png

运行后成功的结果如下图所示:
image.png

至此包已成功部署到服务器:
image.png

引入

  1. 打开要引入的工程,打开与Assets目录同级的Packages下的manifest文件。manifest文件详细参考 Project manifest

image.png

  1. 在dependencies添加对刚刚上传到npm的包名的引用,并且标注版本号,注意包名与刚刚上传到npm的包到package.json里面到name字段相同,版本号与package的version一致。
    image.png
    再添加如下字段
"scopedRegistries": [
    {
      "name": "Iyourcar Registry",
      "url": "http://192.168.6.59:4873/",
      "scopes": [
        "com.iyourcar"
      ]
    }
  ]

dependencies的键都是包名,值是版本号。
指定了scopedRegistries之后,unity在dependencies下如果匹配包名与scopedRegistries中某一项的name字段最符合的,就从最相似的那一项的url下载该包
参考 Scoped Registries

后续更新

部署

将需要更新的工程的package.json的version字段改大,然后
打开命令行, 输入cd,并拖拽Assets上一层文件到 命令行窗口 按下Enter 让命令行进入到Assets上一层的文件夹,然后输入ls,查看当前文件夹下的文件列表,然后输入sh publish.sh。

引入

打开要引入的工程,打开与Assets目录同级的Packages下的manifest文件,将包的版本号与package的version改成与npm部署的一致。


其他参考网站

自定义unity package官方说明文档

官方自定义package及加载参考视频

git subtree用法

UnityPackage的Git依赖说明

package.json丢失问题

Unity使用Package Manager管理自定义插件

【教程】开发Unity PackageManager 插件包


报错集合
  1. 如果在unity拉取自定义package的时候遇到了解析json文件的错误,但是将package.json文本内容拿到json解析网站解析的时候又没有出现任何问题,而且必须字段也没有缺少,这种情况可能原因是一些中文的看不见的字符被检测到了,将官方网站的示例package.json内容拷贝过来,然后在修改为自己所需的内容,这种解决方案是比较理想的。
    我这里遇到的情况是:如果创建package.json的方式是先在unity引擎里面创建c#脚本,然后改后缀名并且在visual studio或者rider里面编辑json,即使json格式正确,在引入的时候也会报错。正确的做法是用系统的文件浏览器需要创建package.json的文件夹,然后右键创建txt文本,再改后缀名为.json,然后双击,选择用系统文本编辑器打开,在里面添加json内容,保存。下图的窗口即为文件浏览器,即系统默认的文件浏览方式。亲测试过:如果一开始使用的是第一种做法,将第一种做法里面的package.json里面的内容复制出来,直接作为第二种做法的内容是没问题的。后续更改json可以用Rider类的 IDE也没什么问题在这里插入图片描述

  2. 在github网页选择子树分支后,给出的git下载地址是主仓库的git地址,在这个地址下找不到package.json然后unity报错,选择了子树分支后,给出的git地址不是子树的git地址,需要再在后面加上文件夹路径或者版本号。

	Cannot perform upm operation: Unable to add package  does not point to a valid package repository. No package manifest was found. Verify the 	repository URL and make sure the package is located in the root folder of 		the repository. [NotFound].See console for more details

另外即使给的url下面是确定已经有了package.json了,但是还是报这个错,是package格式不对,unity这样的报错容易误导人,建议遇到问题时直接将要添加的git克隆下来,本地添加package manager,看下报的是什么错,当本地的报错解决了之后,再提交,尝试从网上添加,这时一般是对了
我在遇到上述问题但是是其他原因时,就用这个方法,结果unity给出的报错是我的unity版本没有写对,我写的是2021.1.12f1c1,然后改成2021.1就可以了,unity版本不是很重要。

  1. 在生成package的工程中,如果asmdef所在文件夹或子文件夹下的脚本引用了一些脚本,但是被引用的脚本其文件夹或者父文件夹没有asmdef,可能会报一些错,这个错是被引用的脚本的类找不到,要注意引用的脚本和被引用的脚本被同一个asmdef文件打入同一个程序集。

  2. You need to run this command from the toplevel of the working tree. 有些命令运行的时候出现这个,需要将命令行执行所在的文件目录跳到.git所在的位置,如图所示:image.png
    位置应该在GithubDebugger上,不应该在Assets文件夹上,执行命令:

cd /Users/wenqinning/RiderProjects/GithubDebugger
  1. 报错:
GUID [9fc0d4010bbf28b4594072e72b8655ab] for asset 'Packages/com.iyourcar.debugui/Scenes/SampleScene.unity' conflicts with:
 'Assets/Scenes/SampleScene2.unity' (current owner)
We can't assign a new GUID because the asset is in an immutable folder. The asset will be ignored.

工程里面的物体与引入包的同名了,将包卸载然后,改掉物体的名字再重新引入包即可。

  1. 报错:
npm ERR! 403  In most cases, you or one of your dependencies are requesting
a package version that is forbidden by your security policy.

这是因为在npm publish 之前没有对当前登录对用户进行验证,参考

How to debug ‘npm ERR! 403 In most cases, you or one of your dependencies are requesting a package version that is forbidden by your security policy.’

7.报错 “No new revisions were found”,我在第一次提交推送完项目后执行subtree split命令时遇到的这个问题,将执行推送的命令行窗口关掉再重新打开新的窗口然后重新执行命令即可。

  1. git是不允许提交一个空的目录到版本库上的,可以在空文件夹下面添加.gitkeep文件,然后提交提交就好了;其实在git中.gitkeep就是一个占位符;可以用其他比如.nofile等文件作为占位符。 参考 git添加空文件夹

最后贴上Unity 常用的.gitignore文件,项目过大所以 额外忽略的FBX, 放到Asset同级目录下,可自行修改

/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd


# Unity3D generated meta files
*.pidb.meta

# Unity3D Generated File On Crash Reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

# FBX Series
*.obj
*.tga

Library/
Temp/
*.sln
*.csproj
*.sln
*.userprefs
*.unityproj
*.DS_Store
obj/
gub.log
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐