Android、iOS、jenkins全自动化打包
主要流程思路【粗略讲处理思路,若遇到具体问题可留言交流】:
1.android的打包命令
2.ios的打包命令
3.jenkins的参数化构建
4.七牛的上传命令等
5.处理ipa的下载操作及ipa过期的监控
6.下载页面h5页面(css,js,html)
7.打包等数据存入数据库
8.分层封装
代码目录结构:
一、pkg_common:一些基础的操作都封装在这个目录
(1)安卓的打包命令、apk处理
(2)ios的打包命令
(3)命令运行封装
(4)ipa的监控
(5)jengkins的参数处理
(6)通知处理
(7)七牛上传处理
(8)二维码处理
比如文件处理:
拷贝文件,获取文件信息(获取包的名字,版本信息,环境信息,图标信息等)、生成下载html页面,创建下载plist文件等等
android的打包上传下载比较简单,重点讲一下ios的打包:
1. ios打包分为三步:清理,编译,导出ipa
(1)清理项目:xcodebuild clean -workspace %s -scheme %s -configuration %s
(2)编译:xcodebuild archive -workspace %s -scheme %s -configuration %s -archivePath %s
(3)导出包:xcodebuild -exportArchive -archivePath %s -exportOptionsPlist %s -exportPath %s
贴一个导出包的代码:
1 from datetime import datetime
2 from pkg_common.cmd import common_run_cmd as cmd
3 from pkg_common.handle_file import find_file as fd
4
5
6 def export_ipa(xch, plist, ext_path, log, wp):
7
8 """
9 :param xch: xcarchive文件及路径
10 :param plist: ExportOptions.plist 文件及路径
11 :param ext_path: 导出ipa包的路径
12 :param log: 日志文件
13 :param wp: 执行cmd的目录
14 :return:
15 """
16
17 """
18 xcodebuild -exportArchive -archivePath /Users/Work/iOS/exrmle/AppStore/20190929171231/covermedia.xcarchive -exportOptionsPlist /Users/Work/iO
19 S/exrmle/AppStore/ExportOptions.plist -exportPath /Users/Work/iOS/exrmle/AppStore/20190929171231/ > /Users/Work/iOS/exrmle/log/03export.log
20 """
21 cmd_export = "xcodebuild -exportArchive -archivePath %s -exportOptionsPlist %s -allowProvisioningUpdates -exportPath %s > %s" % (xch, plist, ext_path, log)
22 print(datetime.now(), '** Export Begin **')
23 cmd.run_cmd(cmd_export, wp).read()
24 with open(log, 'r', encoding='utf-8') as f:
25 for i in f.readlines():
26 if 'EXPORT SUCCEEDED' in i:
27 print(datetime.now(), '** Export Succeed **')
28 break
29 else:
30 error_list = fd.find_log_error(log)
31 for el in error_list:
32 print(el)
33 raise AssertionError('** Export Error **')
ExportOptions.plist文件内容:
分methon的不同有4中类型:ad-hoc、app-store、development、enterprise。
不知道怎么构造的化,用xcode直接导出包后就生成了,compileBitcode最好设置为false,不然容易出错不说,导出时候还很慢。
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>compileBitcode</key>
6 <false/>
7 <key>method</key>
8 <string>ad-hoc</string>
9 <key>signingStyle</key>
10 <string>automatic</string>
11 <key>stripSwiftSymbols</key>
12 <true/>
13 <key>teamID</key>
14 <string>SWM****5PP</string>
15 <key>thinning</key>
16 <string><none></string>
17 </dict>
18 </plist>
包导出后,可以上传到第三方如蒲公英、fir下载,最好还是自己搭建下载页面,如果有七牛云的话,更简单,注意:ipa下载需要是https的。
ipa不像apk一样直接上传后获取下载地址就可下载,需要生成下载plist文件才可以下载到ipa的包。
下载plist文件样式:
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<!-- ipa下载地址 -->
<string>https://pkgcdn.***r.cn/pkg/cover/ipa/rm_cg_iOS/7.0.0/***.ipa</string>
</dict>
<dict>
<key>kind</key>
<!-- 512 x 512 像素的 PNG 图像 -->
<string>full-size-image</string>
<key>needs-shine</key>
<false/>
<key>url</key>
<string> </string>
</dict>
<dict>
<key>kind</key>
<!-- 57 x 57 像素的 PNG 图像,在下载和安装过程中显示 -->
<string>display-image</string>
<key>needs-shine</key>
<false/>
<key>url</key>
<string> </string>
</dict>
</array>
<key>metadata</key>
<dict>
<!-- bundle ID -->
<key>bundle-identifier</key>
<string>com.C***anCha</string>
<!-- APP 版本号 -->
<key>bundle-version</key>
<string>7.0.0</string>
<key>kind</key>
<string>software</string>
<key>subtitle</key>
<string>7.0.0</string>
<!--下载和安装过程中显示的应用的名称 -->
<key>title</key>
<string>rm_cg_iOS</string>
</dict>
</dict>
</array>
</dict>
</plist>
需要维护ipa下载地址、bundle ID、版本信息等即可
然后把这个plist文件上传的服务器,下载地址生成:
“itms-services://?action=download-manifest&url=”加上plist的下载地址,如:
itms-services://?action=download-manifest&url=https://pk**n.thecover.cn/pkg/cover/plist/rm_cg_iOS/7.0.0/rm**7.plist
好了,iOS的打包全流程就这样~搞明白了还是很简单的。
当然,ipa到此还没有结束,ipa还需要上传到苹果市场,也可以通过命令解决。
(1)上传appstore验证:xcrun altool --validate-app -f %s -t ios --apiKey %s --apiIssuer %s --verbose
(2)上传appstore:xcrun altool --upload-app -f %s -t ios --apiKey %s --apiIssuer %s --verbose
这两个命令前提是需要到app store connect 用户-密钥去配置:
apiKey:密钥ID
apiIssuer:issuer ID
配具体步骤:
登录iTunesConnect --->用户与访问--->密钥,至此,生成相应身份的密钥,再将私钥下载下来
下载后需要放到一个固定目录下,'./private_keys'或者'~/private_keys' 或者'~/.private_keys'
或者'~/.appstoreconnect/private_keys'目录下
到此,ipa的包才算处理完成
与iOS相比,Android的打包就简单得多:
1.清理项目:./gradlew clean
2.编译:./gradlew assemble%s%s
3上传:普通上传,不需特殊处理
4.下载:上传后得到的下载地址即可
二、pkg_controller
(1)android的打包流程
(2)ios的打包流程
贴一个ios的打包流程,当然,还可以进一步封装,后续再优化优化。
1 # coding = utf-8
2 # ***iOS打包
3
4
5 import sys
6 sys.path.append('..')
7 from datetime import datetime
8 from PIL import Image
9 from pkg_dao import deal_sql_data as ds
10 from pkg_common.qiniu import common_qiniu as qn
11 from pkg_common.notice import common_notice as notice
12 from pkg_common.qr_code import common_qr_code as qr_code
13 from pkg_common.jenkins import get_jenkins_parameter as get_jenkins
14 from pkg_common.ios import ios_modify_file as mf
15 from pkg_common.ios import ios_build_ipa as build
16 from pkg_common.ios import ios_export_ipa as export
17 from pkg_common.ios import ios_clean_workspace as clean
18 from pkg_common.ios import ios_pod_update as pod
19 from pkg_common.handle_file import zntopy as pin
20 from pkg_common.handle_file import deal_file as df
21 from pkg_common.handle_file import find_file as find
22 from pkg_common.handle_file import common_pkg_info as pkg
23 from pkg_common.handle_file import common_upload as upload
24 from pkg_common.handle_file import create_plist as ipa_plist
25 from pkg_common.ipa_monitor import copy_ipa_monitor as monnitor
26 from pkg_common.handle_file import create_download_html as down_html
27
28
29 # 需要重jenkins获取的参数
30 jks = [
31 'WORKSPACE', # jenkins工作路径
32 'build_environment', # 打包环境 test/product
33 'build_configuration', # 打包模式 Release/Debug
34 'export_environment', # 导出包的模式AdHoc/AppStore/Development/Enterprise
35 'upload_app_store', # 上传app store
36 'BUILD_NUMBER', # 打包次数
37 'is_direct_export' # 是否跳过编译直接导出
38 ]
39
40 dic_jks = get_jenkins.get_jenkins(jks)
41 wk = dic_jks['WORKSPACE']
42 be = dic_jks['build_environment']
43 ee = dic_jks['export_environment']
44 ua = dic_jks['upload_app_store']
45 cfg = dic_jks['build_configuration']
46 ie = dic_jks['is_direct_export']
47 bid = dic_jks['BUILD_NUMBER']
48
49
50 # wk = "/Users/drew/.jenkins/workspace/iOS**"
51 # be = 'product'
52 # ee = 'appstore'
53 # ua = 'T'
54 # cfg = 'Release'
55 # ie = 'T'
56 # bid = '115'
57
58
59 class AppPackaging:
60
61 """
62 iOS打包类
63 """
64
65 def __init__(self, ex_path, con_fig, key_word):
66
67 """
68 变量自定义方法
69 :param ex_path: 输出输入的目录
70 """
71
72 # 日志目录
73 self.lc = ex_path + 'log/01_clean.log'
74 self.lp = ex_path + 'log/02_uppod.log'
75 self.lb = ex_path + 'log/03_build.log'
76 self.le = ex_path + 'log/04_export.log'
77 self.lv = ex_path + 'log/05_validate.log'
78 self.lu = ex_path + 'log/06_upstore.log'
79 self.lx = ex_path + 'log/07_xcarchive.log'
80
81 # 输出文件子目录【存放.plist文件和每次编译后的文件】
82 ex_c = ''
83 if ee.upper() == 'ADHOC':
84 ex_c = ex_path + 'AdHoc/'
85 if ee.upper() == 'APPSTORE':
86 ex_c = ex_path + 'AppStore/'
87 if ee.upper() == 'DEVELOPMENT':
88 ex_c = ex_path + 'Development/'
89 if ee.upper() == 'ENTERPRISE':
90 ex_c = ex_path + 'Enterprise/'
91
92 # 输出孙目录【存放.xcarchive,ipa文件】
93 self.ex_g = ex_c + datetime.now().strftime('%Y%m%d%H%M%S') + '/'
94 # plist文件及路径
95 self.plist = ex_c + 'ExportOptions.plist'
96
97 # 查找当前目录下需要修改环境的配置文件
98 self.f, self.f_p = find.find_file(con_fig, wk)
99 # 定位关键词:指定关键词以定位修改文件的地方
100 self.key_word = key_word
101 # workspace名称
102 self.ws = find.find_file('*.xcworkspace', wk)[0][0]
103
104 def ios_pra(self):
105 """
106 定义iOS打包参数
107 :return:
108 """
109
110 # workspace文件
111 wsn = self.ws + '.xcworkspace'
112 # scheme名称
113 schn = self.ws
114 # 编译后生成的xcarchive文件
115 xch = self.ex_g + self.ws + '.xcarchive'
116 # 需要上传的ipa文件
117 ipa_path = self.ex_g + self.ws + '.ipa'
118 return wsn, schn, xch, ipa_path
119
120 def packaging(self, dic, pod_sign=0, copy_sign=0):
121 """
122
123 :param dic:
124 :param pod_sign:
125 :param copy_sign:
126 :return:
127 """
128
129 desc = ''
130 push_file = ''
131 if be.upper() == 'TEST':
132 desc = '内网测试环境'
133 push_file = wk + dic['str_test']
134 if be.upper() == 'PRODUCT':
135 desc = '外网正式环境'
136 push_file = wk + dic['str_product']
137 if ee.upper() == 'APPSTORE':
138 desc = '外部发布上线【非安装版本】'
139 push_file = wk + dic['str_product']
140 push_file_to = wk + dic['str_to']
141
142 if ie == "F":
143 # 删除xcode缓存文件
144 clean.del_file(self.ws + '*')
145 # 清理项目
146 clean.clean_xcworkspace(dic['wsn'], dic['schn'], cfg, self.lc, wk)
147 # 修改配置文件
148 mf.modify_file(be, self.key_word, self.f_p[0])
149 # 配置阿里推送文件目录
150 if dic['push_sign'] == 1:
151 # 拷贝配置
152 mf.copy_file(push_file, push_file_to)
153 if pod_sign == 1:
154 pod.update_pod(self.lp, wk)
155 # 编译
156 build.build_ipa(dic['wsn'], dic['schn'], cfg, dic['xch'], self.lb, wk)
157 # 编译成功后把.xcarchive文件路径写入log文件
158 df.write_file(self.lx, dic['xch'])
159 # 导出ipa
160 export.export_ipa(dic['xch'], self.plist, self.ex_g, self.le, wk)
161 else:
162 # 读取上次编译的.xcarchive文件目录
163 xch = df.read_file(self.lx)
164 # 导出ipa
165 export.export_ipa(xch, self.plist, self.ex_g, self.le, wk)
166
167 # --------------------------------参数定义-----------------------------
168
169 # ipa名称
170 ipa_name = self.ws + bid + '.ipa'
171 # plist 名称
172 plist_name = dic['project_name'] + bid + '.plist'
173 # plist文件路径
174 file_plist_path = dic['path_plist'] + plist_name
175 # icon 名称
176 img_name = dic['project_name'] + bid + 'ios_icon.png'
177 # 当前包二维码名称
178 qr_name = dic['project_name'] + bid + 'ios'
179 # 当前包二维码上传七牛key名称
180 qn_qr_name = qr_name + '.png'
181 # --------------------------------参数定义-----------------------------
182
183 # -------------------------上传七牛生成二维码及下载页面--------------------
184
185 # 获取APP版本等信息
186 app_image, app_bundle_id, app_version, app_name = pkg.get_ipa_info(dic['app_icon'], wk)
187
188 # --------------------------------参数定义-----------------------------
189 # 通用下载html名称
190 html_name = pin.zn_to_py(app_name) + "_gdh.html"
191 # html文件路径+
192 file_html_path = dic['path_html'] + html_name
193 adg = pin.zn_to_py(app_name) + bid + "ios_adg.html"
194 app_dg_html_path = dic['path_html'] + adg
195 # 通用html生成二维码名称
196 qr_name_html = dic['project_name'] + '_html' + bid + 'ios'
197 # 通用html二维码上传七牛key名称
198 qn_qr_name_html = qr_name_html + '.png'
199 # --------------------------------参数定义-----------------------------
200 # 上传icon图标
201 img_key, img_download_url = qn.qiniu_upload(app_image, dic['project_name'], app_version, img_name, 'img')
202 # 上传ipa文件
203 ipa_key, ipa_download_url = qn.qiniu_upload(dic['ipa_path'], dic['project_name'], app_version, ipa_name, 'ipa')
204 # 生成plist文件
205 ipa_plist.create_plist(ipa_download_url, app_bundle_id, app_version, dic['project_name'], file_plist_path)
206 # 上传plist
207 plist_key, plist_download_url = qn.qiniu_upload(file_plist_path, dic['project_name'], app_version, plist_name, 'plist')
208 # 生成ipa下载地址
209 ios_download_path = 'itms-services://?action=download-manifest&url=%s' % plist_download_url
210
211 # 查询数据库
212 sql_where = {
213 'app_name': app_name,
214 'app_type': 'iOS'
215 }
216 sql1, sql2, sql_a_q, sql_a_o, sql_i_t, sql_i_p = ds.rs(sql_where)
217 app_related = ds.read_sql(sql1)
218 pkg_path = ds.read_sql(sql2)
219 if len(app_related) == 0:
220 app_related = '0'
221 else:
222 app_related = app_related[0][0]
223 if len(pkg_path) == 0:
224 pkg_path = ''
225 else:
226 pkg_path = pkg_path[0][0]
227
228 saq = ds.read_sql(sql_a_q)
229 sao = ds.read_sql(sql_a_o)
230 sit = ds.read_sql(sql_i_t)
231 sip = ds.read_sql(sql_i_p)
232 saq_html = down_html.create_table(saq)
233 sao_html = down_html.create_table(sao)
234 sit_html = down_html.create_table(sit)
235 sip_html = down_html.create_table(sip)
236
237 adg_img = Image.open(app_image)
238 adg_img = adg_img.resize((120, 120), Image.ANTIALIAS)
239 qr_adg_name = pin.zn_to_py(app_name) + bid + 'ios.png'
240 save_file = dic['path_qr_code'] + qr_adg_name
241 adg_img.save(save_file, quality=100)
242 qr_adg_key, qr_adg_download_url = qn.qiniu_upload(save_file, dic['project_name'], app_version, qr_adg_name, 'img')
243 app_dg = {
244 'type': 'ios',
245 'cfg': cfg,
246 'app_version': app_version,
247 'bid': bid,
248 'desc': desc,
249 'dg_url': ios_download_path,
250 'app_dg_html_path': app_dg_html_path,
251 'app_name': app_name,
252 'icon_url': qr_adg_download_url
253 }
254 # 生成app单次下载html
255 down_html.create_html_app_dg(app_dg)
256 # 上传html
257 a_key, adg_url = qn.qiniu_upload(app_dg_html_path, dic['project_name'], app_version, adg, 'html')
258 # 生成二维码
259 qr_save_img = qr_code.create_qr_code(adg_url, app_image, qr_name, dic['path_qr_code'])
260 # 上传二维码图片
261 qr_code_key, qr_code_download_url = qn.qiniu_upload(qr_save_img, dic['project_name'], app_version, qn_qr_name, 'img')
262 # 替换https为http(钉钉不支持https)
263 qr_code_download_url = qr_code_download_url.replace('https', 'http')
264
265 qr_dic = {
266 'qr_code_download_url': qr_code_download_url,
267 'ipa_download_url': ios_download_path,
268 'apk_download_url': pkg_path,
269 'file_html_path': file_html_path,
270 'app_name': app_name,
271 'app_version': app_version,
272 'bid': bid,
273 'v_code': '0',
274 'type': 'iOS',
275 'cfg': cfg,
276 'desc': desc,
277 'saq_html': saq_html,
278 'sao_html': sao_html,
279 'sit_html': sit_html,
280 'sip_html': sip_html
281 }
282
283 # 生成通用下载html
284 down_html.create_html(qr_dic)
285 # 上传html
286 html_code_key, html_code_download_url = qn.qiniu_upload(file_html_path, dic['project_name'], app_version, html_name, 'html', 1)
287 # 通用html生成二维码图片
288 save_html_img = qr_code.create_qr_code(html_code_download_url, app_image, qr_name_html, dic['path_qr_code'])
289 # 上传二维码图片
290 qr_code_key_html, qr_code_download_url_html = qn.qiniu_upload(save_html_img, dic['project_name'], app_version, qn_qr_name_html, 'img')
291 qr_code_download_url_html = qr_code_download_url_html.replace('https', 'http')
292
293 # ------------------------上传七牛生成二维码及下载页面-----------------------
294
295 # 生成钉钉数据
296 app_info = {
297 'buildName': app_name,
298 'buildVersion': app_version,
299 'buildBuildVersion': bid,
300 'buildUpdated': datetime.now(),
301 'buildUpdateDescription': desc,
302 'buildShortcutUrl': html_code_download_url,
303 'buildQRCodeURL': qr_code_download_url_html
304 }
305
306 # 通知钉钉
307 notice.ding_talk(app_info, 'iOS', cfg)
308
309 # 插入数据库
310 sql_dic = {
311 'app_name': app_name,
312 'app_type': 'iOS',
313 'bundle_id': app_bundle_id,
314 'build_num': bid,
315 'version_id': 0,
316 'version': app_version,
317 'icon_path': img_download_url,
318 'qr_path': qr_code_download_url,
319 'pkg_path': ios_download_path,
320 'build_env': be,
321 'build_type': cfg,
322 'export_env': ee,
323 'app_related': app_related,
324 'html_download1': html_code_download_url,
325 'html_download2': adg_url
326 }
327 ds.write_sql(ds.ws(sql_dic))
328 ds.close_mysql()
329
330 # 上传AppStore
331 if ua == 'T':
332 # 验证
333 upload.up_validate(dic['ipa_path'], dic['ios_key'], dic['ios_issuer'], self.lv)
334 # 上传
335 upload.up_app_store(dic['ipa_path'], dic['ios_key'], dic['ios_issuer'], self.lu)
336
337 if copy_sign == 1:
338 # 拷贝ipa文件
339 monnitor.copy_ipa(dic['ipa_path'], app_name)
流程根据自己需要处理,这里的代码涉及数据库交互,数据相关交互还可以进一步封装处理,这样代码可读性更好一点。
三、pkg_dao
主要处理数据交互与数据库配置信息等
不详细描述
四、pkg_view
android打包实现页面
ios打包实现页面
五、resource
资源模块
(1)配置文件
(2)css文件
(3)html文件
(4)plist文件
(5)其他
六、jenkins的配置
主要用的是自由模式的参数化构建
jenkins再加上邮件监控,打包失败自动发布邮件,网上有各种邮件模版:
七、打包成功后通知钉钉
网上有很多例子,这不讲了
败邮件通知:
效果:
(1)钉钉通知:
(2)下载页面
(3)分类下载页面:
包管理平台:
Android、iOS、jenkins全自动化打包的更多相关文章
- iOS使用fastlane自动化打包到fir(最全最详细流程)
# iOS使用fastlane自动化打包到fir(最全最详细流程)1. **首先确认是否安装了ruby,终端查看下ruby版本**> ruby -v终端输出:ruby 2.4.1p111 (20 ...
- iOS如何实现自动化打包
iOS如何实现自动化打包 前言 在我们的日常开发工作中,避免不了会出现这样的场景:需求迭代开发完成之后,需要提供ipa包给QA同学进行测试,一般会执行如下流程:1.执行Git Pull命令,拉最新的代 ...
- ios实现fastlane自动化打包
终于抽出时间来学习自动化打包了,app在测试阶段一天总会经历好几次的打包,每次打包真是身心疲惫,刚打完的包说不定就被测试妹子反应还要微调什么地方,我就真的有气没法出,打一次包怎么也得浪费十几分钟,还不 ...
- 【最新】Android使用jenkins全自动构建打包-Windows版本(Android,Jenkins,360加固,Email,QRcode,参数构建,蒲公英)
Android打包喝咖啡系列(Windows版) 这篇博客主要讲述的内容: 1.windows上部署Jenkins https://jenkins.io 2.基于SVN或Git https://git ...
- Jenkins实现Android自动化打包
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/77102359 本文出自[赵彦军的博客] 1.Tomcat 进入 https://t ...
- iOS Jenkins 自动化打包构建
前言 在测试app项目过程中,通常都是需要开发打测试包给到测试,但是无论是iOS还是Android的打包过程都是相当漫长的,频繁的回归测试需要频繁的打包,对于开发同学影响还是蛮大的.因此在这种情况下, ...
- Android Jenkins 自动化打包构建
前言 在测试app项目过程中,通常都是需要开发打测试包给到测试,但是无论是iOS还是Android的打包过程都是相当漫长的,频繁的回归测试需要频繁的打包,对于开发同学影响还是蛮大的.因此在这种情况下, ...
- Mac Jenkins+fastlane 简单几步实现iOS自动化打包发布 + jenkins节点设置
最近在使用jenkins 实现ios自动化打包发布蒲公英过程实践遇到了一些坑,特意记录下来方便有需要的人. 进入正题: 一.安装Jenkins 1.Mac上安装Jenkins 遇到到坑 因为 Jenk ...
- Jenkins+ Xcode+ 蒲公英 实现IOS自动化打包和分发
Jenkins+ Xcode+ 蒲公英 实现IOS自动化打包和分发 直接入正题: Screen Shot 2015-09-18 at 16.56.20.png Mac上安装Jekins jekins下 ...
- Jenkins 持续集成实现 Android 自动化打包
打 debug 包流程: git pull 分支最新代码 Android Studio:Build - Generate Signed APK 从 IDE 里可以看到,实际上该操作是执行了 assem ...
随机推荐
- tag 转 分支 branch
获得最新 git fetch origin 获取tag git tag tag 转 branch git branch newbranch vtest.1.0.FINAL --- git branch ...
- 2.4g无线私有协议透传方案特色梳理
为什么? 在2.4G这个频段,的确有待你拥挤,有提供高速上网的wifi,有提供短距离数据和云音乐传输的bt,还要各种xx的东西.在wifi和bt无法覆盖的领域,又出来一个2.4G私有协议传输芯片,这 ...
- 基于wifi的音频采集及处理解决方案小结
一沉浮 这些年,一直围绕着音频来做案子,做出来的案子自己都数不清楚了.记得前几年,刚出道的时候,就把wifi音频传输的设备做出来了.可惜的是,当初太超前市场了,鲜有人问.随着时间的推移,在疫情之 ...
- leetcode数据库sql之Delete Duplicate Emails
leetcode原文引用: Write a SQL query to delete all duplicate email entries in a table named Person, keepi ...
- 记录--H5 实现拍照选景框效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 在实际项目中,遇到了需要唤起手机摄像头拍照的需求,最开始是通过<input type="file" hid ...
- 记录--vue.config.js 的完整配置(超详细)!
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间,对部门的个别项目进行Vue3.0+ts框架的迁移,刚开始研究的时候也是踩坑特别多,尤其我们的项目还有些特殊的webpack配置, ...
- objective-c之Class底层结构探索
isa 走位图 在讲 OC->Class 底层类结构之前,先看下下面这张图: 通过isa走位图 得出的结论是: 1,类,父类,元类都包含了 isa, superclass 2,对象isa指向类对 ...
- SqlServer查询表的所有字段属性及其是否是主外键
CREATE PROC [dbo].[sp_help2] @TableName VARCHAR(50) = NULL AS SET NOCOUNT ON SET TRANSACTION ISOLATI ...
- proteus的C51仿真
Proteus的C51仿真 1.实验原理 Proteus是对C51仿真效果比较好的软件了,可以利用丰富的数字资源的外设实现比较接近实际的设计.仿真方法也比较简单,不需要下载,只需要将仿真文件导出到器件 ...
- multisim的支路及总线设计
Multisim的支路及总线设计 1.实验原理 最近在使用multisim设计时,用到了总线和支路设计,这里记录一下,方便以后查阅相关操作.其中主要是总线的使用和支路连接器的使用. 2.实验操作 (1 ...