这里的自定义package指带有特定功能的一些文件做成在别的工程通过package manager加载的包。
功能插件做成自定义packge的特点在于让插件的开发和维护与用户工程的开发文件完全隔离,用户工程不能更改插件内容但是能将插件用于实际开发中。
package可以放置任意格式的文件,在package中的prefab和scene等所有文件不能被更改,只能拖拽复制到当前场景,或者拖拽到Assets文件夹中,拖拽到Assets中之后更改才能被保存。
创建自定义package
unity对自定义package的文件夹结构有一定的要求,开发者需要遵循这些要求制作。详细参考Package layout。
主要如下:
-
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格式如下所示:
示例的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条的问题。
git引入
示例使用2个git分支来开发这个插件包,实际情况数量因人而异。
-
main分支: 插件包开发环境,也就是一个正常的Unity工程,更新工程只通过这个分支,这里通过他上传package所在的整个unity工程。
-
upm分支: 插件包拉取的分支,只提供upm的拉取和安装,不使用git branch upm的方式创建此分支,因为这里的upm分支只能拉取DebugUI下的内容,使用git branch upm创建的分支会将整个上传的工程拉下。
第一次布置并引入
布置好package并上传到git
- 在github登陆后点击头像选择Repository(仓库),进入仓库面板,点击New(创建),填好之后创建仓库.
-
打开终端或命令行窗口 输入cd 然后拖拽项目Assets文件夹上一级文件夹 到窗口并输入Enter 然后输入 git add .gitignore创建gitignore文件或者复制其他unity项目的.gitignore文件到项目Assets文件夹上一级文件夹的位置。.gitignore文件用于忽略提交时候一些特定后缀到文件
-
依次输入如下每一行,输完一行按一次键盘中间的enter:
git init // 在当前选择文件夹下初始化生成git本地配置文件
git add . // 添加当前文件夹下的所有后缀在gitignore之外的文件到暂存区
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网站也是账号密码这个思路。
- 因为Unity Package Manager 通过git访问package manager的时候需要直接找到package.json, 这要求在上传之后需要将前面声明的A文件夹,作为一个子树分支仓库节点。然后将这个git地址输入。
所以输入了上述命令后,紧接着输入
git subtree split --prefix=Assets/DebugUI --branch upm //生成upm分支 将Assets/DebugUI目录放到upm分支
git tag 1.0.0 xx //给upm分支打标签为1.0.0
git push origin xx --tags //将带tag的upm推送上远程服务器
操作过程如下图所示:
这时刷新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部署和引入
环境的安装
-
到官网下载nodejs并安装,mac用户应该不用管这一条,苹果机mac装系统时候自动会安装
-
安装完之后Mac系统下打开终端,windows系统下打开cmd,Mac系统在窗口下输入sudo su将身份变成管理员。
-
输入npm install -g verdaccio安装verdaccio
-
终端输入verdaccio,启动verdaccio,上述操作过程如下图所示
部署
- 创建sh文件并让它与Assets文件夹同级,如下图所示。
.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的情况。
- 输入cd 并拖拽Assets上一层文件到 命令行窗口 按下Enter 让命令行进入到Assets上一层的文件夹,然后输入ls,查看当前文件夹下的文件列表,然后输入sh publish.sh 运行刚刚创建的sh文件, 操作结果如下图所示:
运行后成功的结果如下图所示:
至此包已成功部署到服务器:
引入
- 打开要引入的工程,打开与Assets目录同级的Packages下的manifest文件。manifest文件详细参考 Project manifest
- 在dependencies添加对刚刚上传到npm的包名的引用,并且标注版本号,注意包名与刚刚上传到npm的包到package.json里面到name字段相同,版本号与package的version一致。
再添加如下字段
"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 PackageManager 插件包
报错集合
-
如果在unity拉取自定义package的时候遇到了解析json文件的错误,但是将package.json文本内容拿到json解析网站解析的时候又没有出现任何问题,而且必须字段也没有缺少,这种情况可能原因是一些中文的看不见的字符被检测到了,将官方网站的示例package.json内容拷贝过来,然后在修改为自己所需的内容,这种解决方案是比较理想的。
-
在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
-
在生成package的工程中,如果asmdef所在文件夹或子文件夹下的脚本引用了一些脚本,但是被引用的脚本其文件夹或者父文件夹没有asmdef,可能会报一些错,这个错是被引用的脚本的类找不到,要注意引用的脚本和被引用的脚本被同一个asmdef文件打入同一个程序集。
-
You need to run this command from the toplevel of the working tree. 有些命令运行的时候出现这个,需要将命令行执行所在的文件目录跳到.git所在的位置,如图所示:
位置应该在GithubDebugger上,不应该在Assets文件夹上,执行命令:
cd /Users/wenqinning/RiderProjects/GithubDebugger
- 报错:
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.
工程里面的物体与引入包的同名了,将包卸载然后,改掉物体的名字再重新引入包即可。
- 报错:
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 之前没有对当前登录对用户进行验证,参考