温馨提示:这是一篇私有的package客户端查询的平台搭建文章,牵扯到python中的Django框架,虽和Flutter相关,但客户端的代码并没有关联,请您根据需要进行阅读。
公有的package,对于一个Flutter开发者而言,再熟悉不过,比如常见的网络库dio,存储库shared_preferences等等,我们都可以在官网进行查找和使用,中文地址:https://flutter.cn/,很方便的就可以找到package网址,如下图所示:
点击打开之后,如下图,我们就可以查找想要的三方库。
在一些特定的环境下,自己公司封装的库,不适合于发布到公有的仓库中,那么就需要搭建一套私有的仓库,和Android中的私有Maven是一个道理,私有的服务端仓库,搭建起来很是简单,因为官方已经给我们提供了,地址是:https://github.com/dart-archive/pub_server,我们只需要按照流程,就可以完美的实现,在这里就不过多介绍,本篇重在于解决如何查看,也就是客户端查看,而不是上传,请各位老铁须知。
私有的package存储服务搭建好之后,一般来说就足够了,只需要把使用方式整理成一个文档即可,但是,如果上传的package足够多,而且公司的开发人员又足够多,那么开发一个针对性的查看平台类似与官网提供的查看就很有必要了。
目前客户端查看实现的方案,有官网提供,当然也有一些三方提供,大家可以根据自己公司需求进行选择性使用,这里采用的是自己从0到1开发,旨在一个简单易用。
本篇的内容大概如下:
1、最终的实现效果一览
2、采用哪种语言作为接口开发
3、前端UI设计以及搭建
4、如何获取package对应的相关信息
5、路由设置和页面返回
6、相关总结
一、最终的实现效果一览
UI效果主打简洁,和官网的风格,简单的保持一致,内容区域只展示基本的内容,别的什么也不展示,以动画的形式,展示左右结构,只有简单的检索和列表展示及简单的内容展示。
首页
搜索页面
内容展示页面
右侧为测试内容,点击想要的Item后,以动画的形式滑入。
二、采用哪种语言作为接口开发
既然作为一个客户端查看,难免需要一个服务端作为支持,不然内容从哪来?服务端主要负责提供package检索和内容的返回,客户端负责内容展示,基于这是一个比较小得项目,选择一个轻量级的语言比较好,一开始选的是php,奈何最近一段时间对python比较感兴趣,于是就选择使用python作为服务端语言,使用的是比较成熟的Django框架。
关于Django框架,这里不做过多介绍,后续准备了相关文章进行着重的概述,所以啊铁子们,需要注意,虽是开发的Flutter的私有package查看,但是呢,用的是python,这个大家一定要熟知。
三、前端UI设计以及搭建
关于前端的UI,确实没什么好设计的,都是遵循着极简的模式,能多简单就多简单,一共三个页面,都是html文件,第一个是首页,第二个是搜索和内容展示页,第三个是上传package介绍页。这里着重介绍下搜索和内容展示页面。
搜索和内容展示页面,搜索的时候是以列表的形式展示,点击相关Item后,左边展示列表,右边展示内容,有一个动态切换的效果,这里简单的做了一个小动画。
$(".list_name").each(function () {
$(this).click(function () {
//点击之后查看详情
$(".list_div").animate({marginLeft: "5%", width: "40%"});
setTimeout(function () {
$(".list_content").css("display", "block");
$(".list_content").animate({right: "5%"});
}, 300);
//请求接口信息
$.get("../queryReadMe?fileName=base_lib", function (data) {
let content = data.data;
var converter = new showdown.Converter();
var html = converter.makeHtml(content);
$(".list_text").html(html);
});
});
});
为了支持md文件加载,这里使用了一个第三方showdown.min.js,当然了在实际的开发中,大家可以随意。
关于填充内容,使用的是Django的模板,主要用于分离文档的表现形式和内容,和Vue使用起来很像。
<div class="pub_div">
<div class="pub_input_div">
<input class="pub_input" placeholder="Search packages"/>
<img src="../static/img/pub_search.png" class="pub_search"/>
</div>
<!--搜索结果页-->
<div class="list_div">
{% if count > 0 %}
{% for search in searchList %}
<div class="list_item">
<div class="list_name">{{ search.name }}</div>
<div class="list_author">
最新版本:<span style="font-style: italic;color: #7a8dc5;">{{ search.version }}</span>
作者:{{ search.author }}
</div>
<div class="list_description">{{ search.description }}</div>
<div class="list_time">
{{ search.time }}
</div>
</div>
{% endfor %}
{% else %}
<div class="list_no">暂时没有数据</div>
{% endif %}
</div>
<!--使用详情-->
<div class="list_content">
<div class="list_text">
</div>
</div>
</div>
四、如何获取package对应的相关信息
当服务端搭建完成之后,便可以按照相关流程,上传自己的package,无论谁去上传,最终都会存到一个路径下,比如,我做为测试用的,所有的package都上传到了E盘下的tmp目录下的package-db。
在package-db目录下,存放的就是所有上传到私服的package,目前做为测试,仅上传了一个,我们继续打开:
每个package下存放的就是各个对应的版本号,再往下,就是存放的资源了。
知道了上传的基本目录结构后,一个问题就来了,如何拿到package的相关信息呢?比如名字,时间,版本号,作者,如何使用等?
其实大家,可以发现,在每个版本号的里面都有一个yaml文件,而这个yaml文件里就是我们上传到package时所填的一些信息,如下所示:
我们只需要逐行读取信息就可以拿到了,拿到信息之后,我们就可以用一个数组存储起来,组成我们需要的列表了。
只提供package而不提供如何使用,显然是不科学的,形同鸡肋,会让人懵逼,最终会造成,你这个package怎么使用?方法怎么调?属性怎么使用?没有一个简单的使用说明,会让人望而却步。
但是,使用方式如何获取呢?当我们开源一个库,为了让别人了解如何使用,一般都会在哪里书写呢?README啊,是不是,随便去github上扒拉一个不错的开源,相信都会有一个README文件,同样的,我们再上传package时,尽量也书写一下README文件,在README里书写相关使用方式或步骤即可,有了README文件,在上传的时候就会跟着一起上传,如下图,它是在tar.gz压缩包里:
压缩文件目录:
打开README文件,是不是发现和上边的截图内容展示一样,没错,所谓的package使用方式,就是通过读取压缩文件里的README内容而来的。
通过以上的分析,我们便可以拿到我们想要的内容,如,名字,版本号,描述,作者,上传时间,使用方式等等,具体的代码如下:
# Flutter私有库查询列表页面
def package(request):
key = request.GET.get("key")
packagePath = "E:\\tmp\\package-db"
rootPath = os.listdir(packagePath)
# 遍历,查找一样的
endList = []
for path in rootPath:
if path.find(key) != -1:
# 继续寻找,找到最大的一个版本号
versionPath = packagePath + "\\" + path
versionList = os.listdir(versionPath)
# 找出最大的一个版本号
versionDir = versionList[len(versionList) - 1]
# 遍历Yaml文件后,读取内容
versionYamlPath = versionPath + "\\" + versionDir + "\\pubspec.yaml"
# 读取内容
file = open(versionYamlPath, "r", encoding="UTF-8")
lines = file.readlines() # 读取所有的行数
name = lines[0].replace("\n", "").replace("name: ", "") # 名字
description = lines[1].replace("\n", "").replace("description: ", "") # 描述信息
version = lines[2].replace("\n", "").replace("version: ", "") # 版本号
author = lines[3].replace("\n", "").replace("author: ", "") # 作者
c_time = os.path.getctime(versionYamlPath)
e_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(c_time))
json = {"name": name, "version": version, "description": description, "author": author, "time": e_time}
endList.append(json)
cou = len(endList)
return render(request, "flutter/pubList.html", {"searchList": endList, "count": cou})
五、路由设置和页面返回
每个Django框架都有一个对应的urls文件,也就是路由文件,在这个文件里,我们可以设置我们跳转的页面,请求的接口等信息。
path('flutter/pub', index.pub), # Flutter私有库查询首页面
path('flutter/package', index.package), # Flutter私有库查询列表页面
path('flutter/packageUpload', index.packageUpload), # Flutter私有库如何上传页面
路由指向的页面配置
# Flutter私有库查询首页面
def pub(request):
return render(request, "flutter/pub.html")
# Flutter私有库如何上传页面
def packageUpload(request):
return render(request, "flutter/pubUpload.html")
六、相关总结
基于Django框架,就简单的实现了一个客户端的package查询页面,前边也说过,不一定非得要使用python来作为服务端,使用php或者Java又或者其他语言都是可行的,最主要的就是选择一个自己熟悉的语言,这样写起来才比较顺手。
还有需要注意的是,如果官网和一些三方提供的package查询,能够满足我们的需求,我们也可以直接使用,没有必要再从0到1进行开发。
按照往常的文章风格,最后我都会贴出来源码或者开源地址,但是呢,实在是过于简单,如果大家了解了Django后,就会发现这些都是基本的知识点,所以就不贴了,但是主要的代码,都在文中介绍了。