Canvas iOS - 教育技术解决方案的自动化构建与高效协作工具链

Canvas iOS 工具链:高效构建与协作自动化套件

Canvas iOS 是一套服务于 Instructure 教育科技生态系统的原生 iOS 应用解决方案。它不仅包含 Student、Teacher、Parent 三款核心 App,更提供了一套深度集成于 CI/CD 流程与日常开发的高度自动化工具链。该项目旨在通过智能化的脚本和标准化的流程,将开发人员从繁琐的构建配置、发布流程及代码维护中解放出来,让团队更专注于教育创新体验本身。

功能特性

  • 智能化的 PR 构建触发

    通过在 PR 描述中添加 builds: 指令,可精准控制 CI 仅构建指定的应用(Student/Teacher/Parent),避免资源浪费。支持 builds: All 一键构建全家桶。

  • 一键式应用发布与版本管理

    提供完整的脚本化发布流程。单条命令即可完成版本号更新、Release Notes 自动生成、Git Tag 打标及远程 Bitrise 构建触发,实现从代码提交到应用商店的自动化衔接。

  • 先进的 PR 构建反馈机制

    针对每次 PR 构建,自动生成包含具体 commit 信息、构建时间及可扫码安装的 QR Code 评论。测试人员无需配置环境,扫码即可在真机验证功能。

  • 跨平台组件开发支持(Horizon)

    为 Canvas Career 体验提供了独立的 Horizon 项目,并内置 Web 文本高亮引擎。该引擎通过 XPath 与字符偏移量双重锚定算法,精准定位并高亮 WKWebView 中的任意文本片段。

  • 严格的代码质量与许可合规

    集成 SwiftLint 强制代码风格统一。同时,提供了自动化脚本统一管理所有代码文件的 AGPL 许可头,确保开源合规性。

  • 一站式资源与配置管理

    • 图标自动化:从 Instructure 设计系统自动拉取并生成 SVG/PDF 资源。
    • 密钥混淆:构建时通过异或混淆算法将 License Key 等敏感信息编译进 Data Asset。
    • 国际化同步:通过 S3 自动导入导出 XLIFF 文件,实现与翻译平台的无缝对接。

安装指南

Canvas iOS 工具链主要为开发者体验及 CI 环境设计,无需最终用户安装。若需在本地运行或调试此项目,请遵循以下步骤:

系统要求

  • Xcode: 15.0+
  • iOS Target: 15.0+
  • 依赖管理: Homebrew, Ruby (3.0+), Node.js (18+), yarn
  • 版本控制: Git

分步安装

  1. 克隆仓库

    bash 复制代码
    git clone https://github.com/instructure/canvas-ios.git
    cd canvas-ios
  2. 安装项目依赖 项目依赖 Swift Package Manager (SPM) 及少量 Node 包用于工具脚本。

    bash 复制代码
    # 安装 Node 依赖 (用于图标生成、国际化等)
    yarn install
    
    # 可选:安装用于 PDF 转换的 Python 工具
    pip3 install cairosvg
  3. 生成 Xcode 项目 项目使用 XcodeGen 生成 .xcodeproj,避免 Git 冲突。

    bash 复制代码
    make sync
  4. 配置环境变量(用于发布/国际化) 如需执行发布或同步翻译功能,需设置对应的 Bitrise Token 或 AWS 凭证。

    bash 复制代码
    export BITRISE_TOKEN="your_bitrise_personal_token"
    export AWS_ACCESS_KEY_ID="your_aws_key"
    export AWS_SECRET_ACCESS_KEY="your_aws_secret"

使用说明

场景一:控制 PR 构建范围

开发者在提交 PR 时,在描述中包含特定指令即可决定 CI 构建哪些 App,大幅节省排队时间。

bash 复制代码
# 仅构建 Student 和 Teacher App
builds: Student, Teacher

# 构建所有 App
builds: All

对应代码:scripts/builds/set-require-builds.sh 解析 BITRISE_GIT_MESSAGE 并设置环境变量。

场景二:触发正式版本发布

Release Manager 执行以下命令,脚本将自动更新版本号、提交分支、打 Tag 并触发 Bitrise 的 App Store 构建流。

bash 复制代码
# 语法: yarn release <AppName> <Version>
yarn release Student 7.18.0

对应代码:scripts/release/release.sh 通过 curl 调用 Bitrise API。

场景三:在 WKWebView 中高亮文本(Horizon 项目)

Horizon 模块通过 JavaScript 与原生交互,实现类似"笔记标注"的功能。

javascript 复制代码
// 1. 获取用户当前选中的文本及位置信息
const selection = window.getCurrentTextSelection();

// 2. 设置高亮样式(如背景色、图标)
selection.backgroundColor = "yellow";
selection.borderColor = "red";

// 3. 应用高亮
window.applyHighlights([selection]);

对应代码:Horizon/Horizon/Resources/WebHighlighting.js 提供 applyHighlightsgetCurrentTextSelection 接口。

场景四:处理应用的本地化字符串

导出最新的英文 XLIFF 源文件并推送至翻译平台 S3 桶。

bash 复制代码
yarn export-translations

如需拉取翻译好的语言文件并导入 Xcode 工程:

bash 复制代码
yarn import-translations

对应代码:scripts/translations/export.jsimport.js

核心代码

1. PR 构建智能触发引擎

该脚本通过解析 PR 描述中的 builds: 关键字,动态决定 CI Pipeline 需要构建的 App,有效管理 CI 资源。

bash 复制代码
#!/usr/bin/env bash
# scripts/builds/set-require-builds.sh

# 解析 Bitrise 环境变量中的 Git 提交信息
BUILDS_LINE=$(echo "$BITRISE_GIT_MESSAGE" | grep -i "^builds:" || true)

# 若包含 "student"(不区分大小写),标记需要构建 Student
if [[ $BUILDS_LINE_LOWER == *"student"* ]]; then
    envman add --key REQUIRE_STUDENT --value "true"
fi

# 若包含 "all",标记构建所有应用
if [[ $BUILDS_LINE_LOWER == *"all"* ]]; then
    envman add --key REQUIRE_PARENT --value "true" &&
    envman add --key REQUIRE_TEACHER --value "true" &&
    envman add --key REQUIRE_STUDENT --value "true"
fi

2. 通用归档拆分策略

该脚本通过一次性构建包含三个 App 的通用归档文件,再利用 cpPlistBuddy 快速拆分为独立的 .xcarchive,将传统模式下串行构建的 15 分钟压缩至 5 分钟。

bash 复制代码
#!/bin/zsh
# scripts/archive-all.sh

# 构建包含所有 App 的通用归档
xcodebuild -workspace Canvas.xcworkspace -scheme All -archivePath build/archives/All.xcarchive archive

# 循环为每个 App 生成专属归档
apps=(Student Teacher Parent)
for app in $apps; do
    # 拷贝主归档作为模板
    cp -r $allArchive $appArchive
    
    # 删除其他 App 的二进制文件
    for otherApp in ${(@)apps:#$app}; do
        rm -rf $appArchive/Products/Applications/$otherApp.app
    done
    
    # 修改归档 Info.plist,指向正确的 ApplicationPath
    /usr/libexec/PlistBuddy $appArchive/Info.plist \
        -c "Add :ApplicationProperties:ApplicationPath string Applications/$app.app"
done

3. 基于 XPath 与字符偏移量的精准文本锚定

为了解决 WebView 中 DOM 结构动态变化导致高亮丢失的问题,核心模块实现了双锚点策略:既存储 XPath 用于结构定位,又存储字符偏移量用于容灾恢复。

typescript 复制代码
// WebHighlighting/src/util/RangeAnchor.ts
export class RangeAnchor {
  // 将 DOM Range 转换为可序列化的 Selector
  toSelector(): RangeSelector | null {
    return {
      // 存储起始容器的 XPath 路径
      startContainer: xpathFromNode(textRange.start.element, this.root),
      // 存储在该元素内部的字符偏移量
      startOffset: textRange.start.offset,
      endContainer: xpathFromNode(textRange.end.element, this.root),
      endOffset: textRange.end.offset,
    };
  }

  // 从持久化的 Selector 重建 Range
  static fromSelector(root: Element, selector: RangeSelector): RangeAnchor | null {
    // 通过 XPath 重新查找节点
    const startContainer = nodeFromXPath(selector.startContainer, root);
    const endContainer = nodeFromXPath(selector.endContainer, root);
    
    // 重建文本位置并还原高亮
    const startPos = TextPosition.fromCharOffset(startContainer, selector.startOffset);
    const range = new TextRange(startPos, endPos).toRange();
    return new RangeAnchor(root, range);
  }
}
```FINISHED
YBgybjVjkKVzJKzJoZoHmrhRJT6DO4glvxXXE2sHYTw=
相关推荐
九.九6 小时前
ops-transformer:AI 处理器上的高性能 Transformer 算子库
人工智能·深度学习·transformer
春日见6 小时前
拉取与合并:如何让个人分支既包含你昨天的修改,也包含 develop 最新更新
大数据·人工智能·深度学习·elasticsearch·搜索引擎
恋猫de小郭6 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
deephub6 小时前
Agent Lightning:微软开源的框架无关 Agent 训练方案,LangChain/AutoGen 都能用
人工智能·microsoft·langchain·大语言模型·agent·强化学习
大模型RAG和Agent技术实践7 小时前
从零构建本地AI合同审查系统:架构设计与流式交互实战(完整源代码)
人工智能·交互·智能合同审核
老邋遢7 小时前
第三章-AI知识扫盲看这一篇就够了
人工智能
互联网江湖7 小时前
Seedance2.0炸场:长短视频们“修坝”十年,不如AI放水一天?
人工智能
PythonPioneer7 小时前
在AI技术迅猛发展的今天,传统职业该如何“踏浪前行”?
人工智能
冬奇Lab7 小时前
一天一个开源项目(第20篇):NanoBot - 轻量级AI Agent框架,极简高效的智能体构建工具
人工智能·开源·agent
阿里巴巴淘系技术团队官网博客8 小时前
设计模式Trustworthy Generation:提升RAG信赖度
人工智能·设计模式