分享业务规范
一、分享的链接/口令值获取时机:不适合提前获取再拼接而成,而是需要时候再请求接口
推荐:需要请求接口。(目的是为了省得分享时候再请求)
不推荐:提前给值,然后自己去拼接。(即启动后的某个时刻,请求全局分享配置信息,后续分享的时候使用该信息拼接。)
好处:分享时候,完全不需要前端逻辑,而是完全请求接口,且不用去担心接口内部读库的频次操作。
不推荐的原因/方案缺点:
①不利于后期维护。如要在大部分(但不是全部)分享链接中添加之前遗漏的分享者uid。
②特殊场景,无法达到省请求的目的。如当最终分享链接还要经过后台(如动态短链)时,原本希望不用再请求的最后分享值还是得再请求。
不推荐的原因/方案缺点举例说明如下:
可能形式①:固定的域名链接 + “固定属性参数(常为分享人uid)”+ 其他属性参数
示例:http://www.company.com/app/shareGoods?uid=123&objectType=goodsDetail&objectId=goodsId
- 固定属性参数(常为分享人uid):不一定都需要或不需要
- 优化方案:除其他属性参数外,其他全部由后台提供。即 http://www.company.com/app/shareGoods?uid=123
可能形式②:动态短链(背景:以防被误封)
- 固定属性参数(常为分享人uid):不一定都需要或不需要
二、分享请求接口的参数与返回值结构规范
1、结构规范
请求接口参数与返回值的示例如下:
1 | // request |
代码可点击查看: 分享流程代码示例
2、request 结构可选入参是否从前端直接提供的衡量依据
分享时候,建议从前端直接提供的参数,以分享商品为例
| 可选参数 | 描述 | 是否从前端取 | 原因 |
|---|---|---|---|
| goodsTitle | 商品名称 | 建议 | 直接从前端取,可省去接口通过id去内部获取各种数据 |
| goodsImageUrl | 缩略图 | 建议 | 直接从前端取,可省去接口通过id去内部获取各种数据 |
| 不建议 |
三、复制分享的口令回APP
1、复制分享的口令回APP的流程图
![]()
图片来源:《分享相关(含微信、粘贴板).graffle》中的【粘贴板】
附1、口令介绍
实际口令举例:
1 | { |
理论口令格式(文案为火星文等,且有些口令有内部包含分享链接的情况):
1 | { |
实际口令格式(文案为火星文等,且有些口令有内部包含分享链接的情况):
1 | { |
2、查找哪些SDK使用了粘贴板
四、微信内网页跳转 APP 功能
五、未上架应用的微信每日分享100次限制及分享域名被屏蔽的解决方案
100次限制规定见官方文档:分享与收藏功能
官方对分享的其他问题,请看: 分享与收藏接口
其他解决方案的相关搜索文档:
不上应用市场的企业内部APP,需要放开分享100次限制怎样处理?
2023-05-15 社区运营专员-x
你好,请按照指引提供具体的应用运行图且提供一份说明应用功能目的,只限不做他用加盖公章。
企业内部APP,不上架应用市场,但需要使用微信分享,怎么解决100次限制问题?
2024-07-08 社区技术运营专员–许涛
你好,不支持
iOS使用苹果商务管理的方式上架App Store,但是微信分享次数还是有100次限制,怎么解决?
2024-04-29 社区运营专员-hh
你好,open邮箱账号提供一下
一个不建议用的方案(未落地过):《分享相关(含微信、粘贴板).graffle》中的【未上架应用的微信每日分享100次限制及分享域名被屏蔽的解决方案】
对于iOS开发中未上架应用的微信分享限制问题,微信平台规定若移动应用未上架,则每天的分享量受到限制为100次,这包括分享到会话和朋友圈,主要用于满足调试需求 。针对分享域名被屏蔽的问题,可以采取以下几种解决方案:
- 域名备案:确保分享链接的域名已经完成备案,并且加入微信白名单,避免因备案问题导致域名被封 。
- 使用中转页跳转:设置中转页进行跳转,同时去除来源,保证即使中转页面被封,流量不会流失 。
- 分散域名访问:通过分散和切换域名来降低单一域名的曝光率,减少被封风险 。
- 域名监控系统:使用域名监控系统自动检测域名是否被封,避免使用有不良记录的域名 。
请注意,这些方法可以在一定程度上缓解域名被封的情况,但无法完全避免。开发者应持续关注微信的相关政策更新,以确保分享活动符合规定 。
附1、分享流程代码示例
1 | class ShareUtil { |
附:分享网页的代码如下
1 | class ShareInfoRequestAndSendUtil { |
附2(不用看):分享时候,完全不需要请求接口,而是完全由前端拼接出完整分享的返回结构值
1.1、本地入参1:启动/前后台切换得到的全局Gobal信息中的分享配置模型 objectShareConfig
1 | Map<String, dynamic> objectShareConfig = { |
1.2、本地入参2:为具体object选择分享时候,提供的入参模型 dynamicShareParams
1 | Map<String, dynamic> dynamicShareParams = { |
1.3、计算得到最终分享信息的结构模型(=本地入参1+本地入参2)
1.3.1、计算过程如下
1 | "shareTo": dynamicShareParams["shareTo"], // 分享到哪 |
附,上述各种分享都必备的值,放于临时变量供取及加工,示例如下:
1 | // 各种分享都必备的值 |
口令分享值的获取过程如下:
1 | // 口令分享需要的值; |
结束语
发布业务规范
一、流程
1、方案
参考:
问题:为了优化上传耗时,我们将上传所需的图片压缩提前到用户选择完图片之后。那么当点击上传的时候,需要做哪些处理?
答:1、需要先判断之前的压缩任务是否

1 | class BaseAssetModel { |
结束语
Android打包_多渠道
1 | 查看是否已安装apktool |
结束语
性能优化:搜索优化
搜索优化
一、请求次数优化
1、输入框变化控制
确认修改后才执行接口搜索
iOS开发中如遇到频繁的Http请求,如何取消之前已经发送的Http请求?
核心:怎么使其不频繁。
连续输入
1 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
WebView优化
脑图与概览
点击查看 webView.xmind
参考文章:
概念
1、当App首次打开时,默认是并不初始化浏览器内核的;
只有当创建WebView实例的时候,才会创建WebView的基础框架。
所以与浏览器不同,App中打开WebView的第一步并不是建立连接,而是启动浏览器内核。
先上结论
| 阶段 | 优化方案 | |
|---|---|---|
| (初次/重复)打开时,加载慢 | webview提前(尽可能多的)初始化+全局化 | |
| 加载中,加载慢 | 拦截加载自定义图片(webview_flutter暂不支持) | |
一、(初次/重复)打开时,加载慢:webview提前(尽可能多的)初始化+全局化
背景:有一款基于 cocos2d 的app游戏,其每次启动都很慢。(游戏端说是需要加载游戏引擎,而且引擎本身又比较消耗时间。)
请问1:如何提高初次打开的加载速度?
请问2:如何做到频繁退出进入游戏,不用都走一遍重新加载的流程呢?
| 序号 | 问题 | 解决 |
|---|---|---|
| 1 | 初次打开,加载慢 | 1、webview的在冷启动过后不久的提前初始化 2、初始化的时候多多进行可以初始化的部分,如尝试游戏引擎的加载。 |
| 2 | 重复打开,加载慢 | webview设为全局变量,重复使用 |
优化前后对比小结:
| 方法 | 存在的问题 VS 改进的好处 | |
|---|---|---|
| 未优化 | 每次进入游戏都开启页面,退出游戏都销毁页面。 | 使用上述方法,每次退出再进入该页面都会因为需要重新加载引擎,而导致游戏主页内容的显示很慢,从而严重影响app的使用体验。 |
| 优化后 | 1、游戏使用一个全局GameWebView(其他WebView不用全局) 2、游戏显示使用将webView添加到vc或者window上。 |
全局GameWebView不会被销毁,能够重复使用,提升加载速度。 ①加载过的游戏,下次再进入不用重新重新加载引擎,有效的跳过loading的过程,极大的改善了用户体验。 |
附1:游戏引擎能否直接在原生上提前加载?
答:常见做法:构建出含Cocos的原生工程,然后将自己的功能添加上去。见 Cocos Creator 上原生平台二次开发指南
存在问题:不能自己在原生上添加游戏引擎。 Cocos Creator 引擎定制工作流程 也只是将其自己编译器创建的项目的引擎定制。
最终结论:游戏引擎没办法在原生上提前自己加载。
背景:如何将 Cocos Creator 构建出来的工程用正确的姿势接入Flutter 工程
附2:一个视图实例被添加后,再被添加到其他地方后的效果
此需求背景:《页面跳转相关(路由)》中【四、游戏与app跳转交互优化调研】
测试过程见附录 附1:测试一个视图实例被添加后,再被添加到其他地方后的效果
| 被使用的方式 | 使用的结果 | ||
|---|---|---|---|
| 1 | 一个视图实例添加到一个vc上的两个container上 | 视图只显示在后面设置的位置 | |
| 2 | 一个视图实例添加到不同viewController | 视图只显示在后面设置的位置。则代表回来的时候需要重新更新视图位置。 |
二、加载中,加载慢
方案1: 进行 Scheme 拦截,利用 WKURLSchemeHandler
解决:加载自定义图片,将webView的图片数据改为app的图片数据(Flutter现有的webview_flutter暂时不支持,如要需要自己修改)
参考文档:
「拒绝踩坑」唯一一种拦截 WKWebView 资源请求的方式 => 「最佳实践」WebView 预加载与资源缓存 => WKWebView实现请求拦截,http/https/file等 => WKURLSchemeHandler 的能与不能 代码示例见 ViewController.m
h5中
1 | <h3 id="photo"> 自定义图片:canineschool-avatar://photo </h3> |
app中
1 | let configuration = WKWebViewConfiguration() |
[WKURLSchemeHandler 拦截https时引起网络请求也被拦截了,如何重定向](#WKURLSchemeHandler 拦截https时引起网络请求也被拦截了,如何重定向)
方案2: 下载并解压zip,app加载本地静态文件
在WebView中加载本地资源:使用file协议在WebView中加载沙盒目录中的资源。
跨域问题:
方法1:在后端设置CORS(跨源资源共享)策略,允许来自特定来源的请求。
方法2:资源通过js来app中获取再回到web中显示。
方案3:在app中内置一个 WebServer
其他离线方案:
思考:小程序
小程序并不是一个简单的、优化过的网页,而是一个混合架构,可以理解为:
1 | 小程序 = Native原生容器 + WebView渲染 + JS引擎 + 离线包机制 |
小程序的页面栈管理,像小程序一样支持多页面:
- 每个页面独立的WebView
- 前进/后退时切换WebView而不是重新加载
- 保存每个页面的滚动位置和表单状态
小程序容器的核心精髓:
核心是要先下载离线包zip,然后用webview加载远程Url映射成用webview加载本地离线包中的html。html中的css、js、图片等资源也映射成本地?然后变成一个路由栈管理加载多个本地的html了?
三、打开后,白屏
1、白屏的原因及原理
-
iOS设备上造成白屏的真正原因只有两个:内存使用过度、进程通信机制出现错误。
2、白屏的解决
理想情况(不一定白屏都会调用到):
1 | //进程终止(内存消耗过大导致白屏) |
其他处理方式:
白屏的像素判断法:iOS WKWebView白屏的像素检测方法 或 iOS WKWebview 白屏的像素检测实现
webview截图 ==> 缩放图片,为了减少待会遍历的像素点 ==> 遍历像素点,判断白色像素占比超过95%则认定为白屏
1 | totalCount++; |
白屏的 webView的子视图WKCompositingView 不存在的判断法:白屏时 WKCompositingView 为空
附:WKCompositingView 也是我们在做 WebView同层渲染 的时候经常会遇到的类。
1 | // 判断是否白屏 |
其他解决方案:
| 白屏判断点 | 参考文章 | |
|---|---|---|
webView的 url 、 title 、 document.body.innerHTML 为空 |
WKWebView 白屏处理 |
四、使用中的交互
1、常规
WKWebView 注入js代码: 001-UIKit-CQDemo-Flutter 中的 flutter_webview_kit
2、全局webView下如何正确返回前一页
见 《webview的一生.graffle》中的【全局webView下如何正确返回前一页】版面
五、WebView拦截请求的问题
阿里云官方文档: WKWebView使用私有API进行注册拦截请求
1、WKURLSchemeHandler 拦截https时引起网络请求也被拦截了,如何重定向
当使用WKURLSchemeHandler拦截https的图片时候,其自然的也会把网络请求也拦截了,需要将那些网络请求重定向。
为了区分出不同的https,可以通过获取url地址的扩展名,如 jpg、png、txt、MP4等。
1 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { |
六、WebView同层渲染
原理:
同层组件的目标是将原生组件渲染在与其他 Web 组件同一层级中。
在 iOS 中,我们使用 WKWebView 来创建 Web 视图,通常 WKWebView 内核会将多个组件共同渲染到同一个 WKCompositingView 上,这个 View 是一个原生的 UIView 子类。但是如果某个 HTML 标签的 style 设置了 overflow: scroll 属性,并且内容超出容器的大小,WKWebView 就会为其单独的创建一个 WKChildScrollView,因此我们可以找到这些 View,并和对应的 Web 组件一一关联起来,就可以将原生的组件渲染到这个 View 中,从而实现同层渲染。
1、同层渲染需求背景:
Webview 资源离线化之后不需要从后端拉取资源,省去了资源加载耗时减少等待时间,用户体验得到了明显提升,但受限于 Webview 的天生限制在某些场景下仍然能感受到与原生明显的体验落差。比如输入框弹出键盘时的页面卡顿、图片较多的页面内存占用过从后台回来前台时页面被重新加载、WebP 图片支持碎片化、图片不能跨页共享内存、视频播放组件体验不佳等问题。在 Webview 本身受限的情况下,如何在体验上向原生靠近是我们不得不面对的问题。如果能将影响用户体验的关键可交互组件用原生组件进行替换可以从根本上解决体验不如原生的问题。这部分内容我称为: WebView原生化。
Webview 原生化是指把 Webview 内部分占位 DOM 元素用原生组件进行替换,原生组件与原始 Webview 混合便得到了用户看到的最终界面。
组件替换有两种方式,
蒙层方案:在 Webview 的直接上层添加原生视图蒙层,把原生组件添加到蒙层上占位 DOM 对应的位置。缺点:当一个原生组件被添另到 Webview 上时它永远处顶层,不会被 Webview 内的弹窗覆盖,在滚动时原生组件会盖住原本应被显示的区域。
同层渲染方案:另一种是将原生组件添加到 Webiview 渲染时与占位 DOM 对应的合成层(独立出来的原生视图)上,下面会对比两种方案的差异。
以上引用内容摘自:微信小程序『同层渲染』技术是怎么回事? 强烈建议点开原文再看一遍。
2、同层渲染实现示例
关键问题:如何映射 DOM 到原生视图?如何在原生视图树中查找 「DOM」
「同层渲染」则是将原生组件直接渲染到 WebView 层级上。
2.1、入门简单实现
-
具体Demo示例可见SameLayerRender
实现步骤:
1、创建一个可以生成WKChildScrollView原生组件的 DOM 节点
2、传递给客户端查找到该 DOM 节点对应的 WKChildScrollView 原生组件的必要信息
3、客户端根据传来的信息找到对应的原生组件,并将原生组件挂载到该 WKChildScrollView 节点上
2.2、微信小程序实现
( 微信 Skyline 渲染引擎类似 Flutterr 的 SkyEngine)


3、其他参考文档
容器 URL 统一化建设(一个 URL 地址可按需动态配置渲染成 H5、Native 等页面),小程序容器建设,Flutter 容器建设,容器的快照缓存、预渲染、混合渲染等优化与能力相关建设
其他
优化待处理的文章
iOS WebView/H5 调试新姿势
附1:测试一个视图实例被添加后,再被添加到其他地方后的效果
测试代码:详见 AppCommonJSCollect 中的 SharedNormalView 、 SharedWebView
1.1、测试一个视图实例添加到一个vc上的两个container上
1.2、测试一个视图实例添加到不同viewController
阶段1:进入新页面的时候,使用之前共享的视图
阶段1结果:虽然第二页复用了第一页中的视图,但是从第二页回来的时候,第一页的视图不见了。
阶段2:在阶段1的基础上,补充回来的时候(viewWillAppear),需要重新更新视图的布局
阶段2结果:视图显示正确了
End
H5与APP的交互
一、app内的h5调用app的网页
第1.1节:h5js(app内的h5与app互相调用JS方法及传值)
二、app外的h5直接打开app
第1.2节:h5 open app(app外的h5直接打开app)
三、通知(推送/站内信)打开app
1、站内信
接收到通知后,
- 调用
相关脚本的本地测试方法
本地代码测试:
将文件放置到 /Library/WebServer/Documents/ 下,比如将 dvlp_h5_open_app_app_route_url_demo.html
放置:/Library/WebServer/Documents/h5_native_interacte/h5_open_app/dvlp_h5_open_app_app_route_url_demo.html
1、基本访问测试
访问:http://localhost/h5_native_interacte/h5_open_app/dvlp_h5_open_app_app_route_url_demo.html
2、参数携带测试
访问:http://localhost/h5_native_interacte/h5_open_app/dvlp_h5_open_app_app_route_url_demo.html?fileUrl=dvlp_h5_open_app_browser_url_demo.json
3、更多参数使用测试可参考 h5_open_app 或 h5js
小程序容器技术
小程序容器技术
React Native 的 Text 组件转换为 iOS 的原生 UILabel ,是怎么实现这一过程的?
1 | <view class="container"> |
1 | .container { |
1 | import UIKit |
在实际的小程序容器中,你需要一个完整的模板引擎来解析WXML,并将其转换为iOS的UI组件。你还需要一个样式引擎来解析WXSS,并应用样式到对应的UI组件上。
End
详解Exception异常处理
好文分享:
- Flutter中异常处理:必须一定要看。
一、异常的捕获
同步异常通过 try-catch 机制捕获
1 | // 使用 try-catch 捕获同步异常 |
异步异常采用 Future 提供的 catchError 语句捕获。
1 | // 使用 catchError 捕获异步异常 |
二、异常的上抛
异步异常的上抛
1 | // 使用上文中自己建的异步方法 await simulate_get(url) 来模拟 |
进行如上的上抛操作后,
1 | // xxxPage.dart |
判断网络异常
1 | checkNetwork() async { |
Git代码同步
1、拉取最新代码、提交
1 | cd CQApp-api-mongodb/ |


上传成功,我们通过网站或者sourcetree等查看效果

1、问题1:未配置用户名和邮箱

解决配置用户名和邮箱
1 | 1、全局配置:使用 --global 修饰后设置的全局的用户 |
使用命令:git config –list 可查看当前用户信息以及其他的一些信息

2、拉取提交省去密码输入的技巧–ssh
1 | ssh-keygen -t rsa -C "ecs_aliyun" |

到 github/gitee/gitlab 上添加对应的ssh

四、提交云服务器代码
- 1、从服务器重新拉代码,将本地代码更新为服务器上的最新代码
1 | git pull |

- 2、查看本地代码状态,是否有待提交的代码
1 | git status |
- 3、将本地代码全部提交
1 | git add . |
- 4、commit提交并添加注释
1 | git commit -m "我是提交的注释" |
如果提交过程中出现如下问题:

请先根据提示,设置全局邮件和用户名,以让其他开发者可以看到是谁提交。配置前和配置后,可使用
1 | 查看 |

设置完后,重新执行
1 | git commit -m "我是提交的注释" |
即可。接下来就只剩最后一步,就可正式提交完成了。
- 5、将本地的 master 分支推送到 origin 主机的 master 分支。
1 | git push origin master |
更多 git push用法,查看官网https://www.runoob.com/git/git-push.html

结果:
