feat: 新增 Android/iOS 零依赖 APNG 适配器参考实现 - #1627
Open
lingzeanlan wants to merge 3 commits into
Open
lingzeanlan wants to merge 3 commits into
lingzeanlan wants to merge 3 commits into
Conversation
lingzeanlan
requested review from
elixxli,
iPel,
luoyibu,
ruifanyuan,
zealotchen0 and
zenipchen
as code owners
August 14, 2026 04:32
KuiklyAI
reviewed
Aug 14, 2026
KuiklyAI
left a comment
Collaborator
There was a problem hiding this comment.
🤖 KuiklyAI Code Review
基本信息
- PR:#1627 · feat: 新增 Android/iOS 零依赖 APNG 适配器参考实现
- 作者:lingzeshanhai main ← apng-lite-adapters
变更概述
- 干了什么:新增 Android(
KRAPNGViewAdapterLite.kt)与 iOS(KRAPNGViewHandlerLite.h/.m)两个零第三方依赖的 APNG 宿主适配器,手工解析 APNG 块结构、逐帧重建标准 PNG 交系统解码器播放,并在docs/API/components/apng.md补充文档。纯新增文件,不动现有 demo 适配器与构建。 - 解决什么:对齐作者声明意图——为不希望引入 APNG4Android / SDWebImage 的业务提供可拷贝的零依赖参考实现。
- 方案 & 合理性:落在宿主扩展层(
androidApp/iosApp的 demo 适配器目录与 render-expand 目录),符合「各core-render-*只依赖平台原生 API、demo 只依赖 core」的边界;iOS 侧不做+load自动注册以避免与已有KRAPNGViewHandler的+load顺序不确定,由业务显式注册,合理。适用边界(仅全帧、解析失败降级静态图)在代码注释与文档中均有标注,清晰。
需要关注的问题
- Android 侧
repeatCount=0的语义与 Kuikly 契约不一致:契约约定 0=无限循环,当前实现 0 时回退到文件num_plays,当文件num_plays!=0时会变成有限播放,与 iOS 侧(0=无限)和现有KRAPNGViewAdapter行为都不同。详见 inline。 - Android 与 iOS 对「单帧跨多个 IDAT/fdAT」的处理不一致:iOS 会累积后 flush,Android 只取第一个 chunk,会得到残缺帧。两端同为参考实现,建议对齐。详见 inline。
- iOS 侧每轮播完都会回调
apngImageView:playEndLoop:,会触发框架animationEnd事件;而现有 handler 只在停止时回调一次。无限循环场景下会持续触发「播放结束」事件,与事件语义不符。详见 inline。
文档同步
docs/API/components/apng.md 新增「零第三方依赖参考实现」一节,注册方式与适用边界与代码一致,链接指向正确文件,无影响 ✅。
KuiklyAI
reviewed
Aug 14, 2026
KuiklyAI
left a comment
Collaborator
There was a problem hiding this comment.
🤖 KuiklyAI Code Review
这一笔提交(style: translate comments to English)只把注释从中译英,没有动任何逻辑代码——逐行核对过,所有改动行的 +/- 只是行内注释文案替换,解析、调度、播放计数逻辑均无变化。
因此上一轮提的三点仍然 open:
- Android
repeatCount=0回退到文件num_plays的语义,与 DSL(0=无限)、现有KRAPNGViewAdapter、iOS Lite 三方都不一致; - Android 解析端首帧遇到第一个
IDAT就 flush 并置pendingFirstFrame=false,单帧拆成多个IDAT的文件会丢数据(iOS 侧用pendingIdat累积是对的,建议两端对齐); - iOS
p_advanceFromIndex每轮播完都回调playEndLoop:,而KRAPNGView.m里这个回调直接触发animationEnd事件——无限循环场景每轮都会误触发一次「动画结束」,建议只在真正播完或stopAPNGAnimating时回调。
这轮没有新增 inline 问题。
…late multi-chunk frame data, fire playEnd only on true completion or explicit stop
Author
|
感谢 review,三点已全部修改(commit 547396f):
|
KuiklyAI
reviewed
Aug 14, 2026
KuiklyAI
left a comment
Collaborator
There was a problem hiding this comment.
🤖 KuiklyAI Code Review
增量盘点(commit 547396f)
上一轮提的三条都改到位了,已逐条回复「已解决」:
- Android
repeatCount=0语义 — 移除了numPlays字段和acTL解析分支,0不再回退到文件num_plays,注释与停止条件都改为0 = loop forever (DSL contract),与IAPNGView.setRepeatCount契约(「默认 0 为无限次」)和现有KRAPNGViewAdapter(setLoopLimit(0)= 无限)对齐。✅ - Android 多块帧数据丢失 — 用
pendingIdat: ByteArrayOutputStream累积同一帧的多个连续IDAT/fdAT,flushFrame()在下一个fcTL或IEND时统一 flush,与 iOS 侧pendingIdat+flushFrame写法一致,两端不会再对同一文件产生不同的解析结果。✅ - iOS 每轮回调
playEndLoop— 抽出p_notifyPlayEnd,只在自然播完(playedLoops >= maxLoops)和显式stopAPNGAnimating(wasAnimating守卫,避免 dealloc 误触发)两种情况各回调一次,与KRAPNGViewHandler.m在stopAPNGAnimating回调一次的语义一致,框架侧animationEnd不再被无限循环每轮触发。✅
本次新改动评估
通读了 HEAD~1..HEAD 的全部 hunk(Android adapter + iOS handler 各一处),未发现引入新的功能或兼容性风险,也没有遗留的对 numPlays/pendingFirstFrame 的悬空引用。代码可直接合入。
Author
|
三条 review 意见均已修复并 resolve(commit 547396f)。CLA 已签署,mergeable 状态正常。麻烦各位 code owner 抽空 review,感谢!@elixxli @iPel @luoyibu @ruifanyuan @zealotchen0 @zenipchen |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
APNG组件在 Android/iOS 是宿主扩展,需要业务自行实现适配器。目前 demo 工程的两个参考实现均依赖第三方解码库:KRAPNGViewAdapter依赖 APNG4Android(com.github.penfeizhou.android.animation:apng)KRAPNGViewHandler依赖 SDWebImage(SDAnimatedImageView)对于不希望引入这类第三方库的业务(包体积/合规审计/依赖收敛场景),缺少一个可直接使用的零依赖选择。
改动
新增两个零第三方依赖的 APNG 适配器参考实现(单文件、可直接拷贝使用):
KRAPNGViewAdapterLite.kt——手工解析 APNG 块结构(IHDR/acTL/fcTL/IDAT/fdAT),逐帧重建标准 PNG 交BitmapFactory解码,Handler按帧延时切帧;KRAPNGViewHandlerLite.h/.m——同一解析思路,帧数据交UIImage解码,dispatch_after+ frameIndex 守卫调度;CRC32 自实现,不引入 libz;docs/API/components/apng.md新增「零第三方依赖参考实现」一节,说明注册方式与适用边界。解析失败或不含动画帧时降级为静态图显示,不崩溃。
适用边界(已在代码注释与文档中标注)
仅支持「全帧」APNG(每帧尺寸 = 画布尺寸、offset = 0、blend/dispose = 0)。常见导出工具默认产出全帧,覆盖图标/加载动效等大多数场景;需要局部帧/帧合成的复杂 APNG 仍建议使用第三方解码库适配器。
测试
在业务项目(Kuikly 2.23.2)真机验证:Android/iOS 双端 APNG 正常解码播放、播完定格末帧、repeatCount 语义生效;解析失败路径降级正常。
说明
+load自动注册(demo 中KRAPNGViewHandler已在+load注册,两个+load并存时生效顺序不确定),由业务显式调用+registerToKuikly。