CocoaPods

Activity

Stars and mentions · Last 30 days, Oct 5 – Nov 3

GitHub stars9
Mentions2
01234Oct 5Oct 19Nov 3
UTC days · repositories CocoaPods owns1 repository

Top repositories

CocoaPods’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside CocoaPods’s account where CocoaPods opened or reviewed pull requests in the past 365 days.

Who noticed CocoaPods

Everyone who starred or forked CocoaPods’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

2posts
Nov 40 posts
  1. Flutter Video Editor in 6 Steps: Banuba SDK Setup, Entry Screens and Export A Flutter video editor built on Banuba's ve_sdk_flutter plugin is one Dart call that opens a native recording and editing screen and returns the exported file paths to your code. The setup is six steps: pin the package, configure iOS, configure Android, launch the editor, pick an entry screen, and set the export. Banuba Video Editor SDK is a production-ready mobile video editing engine for iOS, Android, Flutter and React Native. We build it, so this guide uses our plugin, and the comparison near the end also covers the open-source Flutter packages we do not sell. What do you need before you add a video editor to Flutter? You need four things: - A license token. Banuba issues it with a 14-day free trial of the Video Editor SDK, and the plugin's pub.dev page says no credit card information is needed. Without a token, every call fails with an error code you will meet in Step 4. - A Flutter toolchain at or above the plugin's floor. The pub.dev page lists Dart 3.3.0, Flutter 3.19.2, Android 8.0+ and iOS 15.0+. - Native tools for both platforms. Our requirements pages list Kotlin 2.1+ or Java 17, the Camera 2 API and OpenGL ES 3.0 on Android, and Swift 5.9, Xcode 26.0 and iOS 15.0 on Apple devices. - Physical devices. Our Android requirements mark x86-64 as limited support and x86 as not supported, so an emulator image is a weak place to judge the editor. Step 1: How do you install the Flutter video editor plugin? Add the package with the version pinned: dependencies: ve_sdk_flutter: 0.48.1 Then run flutter pub get. The ve_sdk_flutter package depends only on flutter and plugin_platform_interface, so it does not pull a media library into your Dart dependency tree. The media engine arrives through CocoaPods and Gradle in the next two steps. Pin the exact version on purpose, and read the changelog rather than the version number. Some releases track native SDK versions: 0.43.0 supports Video Editor 1.52.0 and 0.44.0 supports 1.53.0, so a minor bump can change native behavior under the same Dart code. Others touch nothing functional at all, which is what 0.48.0 and 0.48.1 did, updating the package description, repository link, topics and homepage. Step 2: What does iOS need? Two edits. First, add Banuba's spec repositories at the top of ios/Podfile, as the plugin integration guide shows: platform :ios, '15.0' source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' Second, add the four usage descriptions to ios/Runner/Info.plist: <key>NSAppleMusicUsageDescription</key> <string>This app requires access to the media library</string> <key>NSCameraUsageDescription</key> <string>This app requires access to the camera.</string> <key>NSMicrophoneUsageDescription</key> <string>This app requires access to the microphone.</string> <key>NSPhotoLibraryUsageDescription</key> <string>This app requires access to the photo library.</string> Run pod install inside ios, then select your Development Team under Signing & Capabilities. Replace the sample strings with wording that tells your users why you need each permission. Step 3: What does Android need, and how do you keep the APK small? On Android, the size decision is the main one. Our documentation gives these additions to your app's download size, and we did not re-measure them for this article: | What you ship | Android | iOS | | :-- | :-- | :-- | | Core editor | 25 MB | 14 MB | | Full bundle | 45 MB | 45 MB | | Editor with face AR features | 45 to 90 MB | 45 to 140 MB | Two switches move you between those rows. Turn off face AR if you do not need masks. Add ENABLE_FACE_AR=false to android/gradle.properties, and this line to the Podfile: ENV['ENABLE_FACE_AR'] = 'false' Filter processor architectures. The integration guide notes that each architecture adds megabytes. Ship ARM only: ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } Upload an Android App Bundle as well. Our Android docs state that with a bundle, the per-device library comes out 24 to 26 MB smaller than the documented figure, because Google Play serves each device only its own architecture. Step 4: How do you open the video editor from Dart? This is a complete lib/main.dart. One button opens the camera screen, and the result or the error comes back to the same widget: import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:ve_sdk_flutter/errors.dart'; import 'package:ve_sdk_flutter/export_data.dart'; import 'package:ve_sdk_flutter/export_result.dart'; import 'package:ve_sdk_flutter/features_config.dart'; import 'package:ve_sdk_flutter/ve_sdk_flutter.dart'; // Passed at build time: flutter run --dart-define=BANUBA_TOKEN=your_token const _licenseToken = String.fromEnvironment('BANUBA_TOKEN'); void main() => runApp(const MaterialApp(home: EditorLauncher())); class EditorLauncher extends StatefulWidget { const EditorLauncher({super.key}); @override State<EditorLauncher> createState() => _EditorLauncherState(); } class _EditorLauncherState extends State<EditorLauncher> { final _veSdk = VeSdkFlutter(); String _status = 'No clip yet'; // Step 6: a 720p file in H.264 plus a file at device-chosen quality static const _exportData = ExportData(exportedVideos: [ ExportedVideo( fileName: 'clip_720p', videoResolution: VideoResolution.hd720p, useHevcIfPossible: false, ), ExportedVideo( fileName: 'clip_auto', videoResolution: VideoResolution.auto, ), ]); Future<void> _openEditor() async { final config = FeaturesConfigBuilder().build(); try { final ExportResult? result = await _veSdk.openCameraScreen( _licenseToken, config, exportData: _exportData, ); if (!mounted) return; setState(() { _status = result == null ? 'Editor closed before export' : 'Exported: ${result.videoSources.join(', ')}'; }); } on PlatformException catch (e) { if (!mounted) return; setState(() => _status = _describe(e)); } } String _describe(PlatformException e) { switch (e.code) { case errCodeSdkNotInitialized: return 'License token is empty or invalid'; case errCodeSdkLicenseRevoked: return 'License revoked or expired'; case errCodeMissingHost: return 'No Activity or ViewController to show the editor'; case errCodeInvalidParams: return 'The editor received invalid input'; case errCodeMissingExportResult: return 'The editor could not export the video'; default: return 'Error ${e.code}: ${e.message}'; } } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(_status), const SizedBox(height: 16), ElevatedButton( onPressed: _openEditor, child: const Text('Open video editor'), ), ], ), ), ); } } openCameraScreen returns Future<ExportResult?>. A null result means the user closed the editor without exporting, so a user who backs out halfway still leaves your screen with a defined status. The plugin defines five error codes in errors.dart. The three below are the ones that stop a first run, and a fourth failure mode after them throws nothing at all. ERR_SDK_NOT_INITIALIZED The plugin's comment on this code reads: "Error occurs when the sdk cannot be initialized with provided license token: invalid, empty". With the snippet above, it usually means the app was started without --dart-define=BANUBA_TOKEN=..., so the constant is an empty string. ERR_SDK_LICENSE_REVOKED The license has been revoked, and the plugin's own comment says to contact Banuba. In the integration sample, the same code also covers an expired license, which is what a finished 14-day trial looks like from Dart. ERR_MISSING_HOST The editor is a native screen, so it needs an Activity on Android or a ViewController on iOS to present from. This code means none was available, which points at calling the plugin before the first frame has rendered, for example from main() or initState(). "New UI is not available from Trimmer screen" This one is not an error code, and that is what makes it expensive to debug. FeaturesConfigBuilder sets enableEditorV2 to true by default, and with the new UI enabled the plugin refuses the trimmer entry point: it writes that line to the debug console and returns null without throwing. From the snippet above, the only thing you see is "Editor closed before export", as though the user had backed out. If you want openTrimmerScreen, turn the new UI off for that call: final config = FeaturesConfigBuilder() .enableEditorV2(false) .build(); Step 5: Which entry screen should the editor open with? VeSdkFlutter in 0.48.1 exposes eight entry points. Each takes the token and a FeaturesConfig, and each returns the same ExportResult: | Method | Extra input | Starts the user on | | :-- | :-- | :-- | | openCameraScreen | none | Recording | | openPipScreen | one video path | Picture-in-picture over an existing clip | | openTrimmerScreen | list of video paths | Trimming the clips you pass | | openEditorScreen | list of video paths | The editing timeline | | openAiClippingScreen | none | AI clipping, starting from the gallery | | openTemplatesScreen | none | Video templates | | openDraftsScreen | none | Saved drafts | | openGalleryScreen | none | The media gallery | openPipScreen takes one video path on top of the token and config, and openTrimmerScreen and openEditorScreen take a list of paths, which you get from a picker such as image_picker. The other five need nothing else. Two things in the 0.48.1 source are worth knowing before you build on this table. openTrimmerScreen is the one that returns null under the default config, as described above. And openEditorScreen accepts an optional trackData argument that goes nowhere: the plugin serializes track data and sends it to the native side from its internal open method, but the editor entry point does not forward the argument to it. Passing a track there is a silent no-op today, so preload audio another way until a release says otherwise. Each screen is trimmed through FeaturesConfigBuilder. Setting supportsBeauty and supportsMasks to false in CameraConfig removes the beauty and mask controls from the camera, and supportsVoiceOver: false in EditorConfig removes voice-over, which our docs mark as Android only. Step 6: How do you control the exported file? Without ExportData, the plugin exports one video at auto quality, which our docs describe as chosen from the device's hardware. With it, you name each file and pick a VideoResolution. The enum has nine values: seven resolutions from vga360p through vga480p, qhd540p, hd720p, fhd1080p and qhd1440p to uhd2160p, plus auto and original. The file type differs by platform. Our docs state that the video is exported as .mp4 on Android and .mov on iOS, so do not hard-code an extension when you upload. Three settings change what lands on disk: 1. useHevcIfPossible: false switches the file to H.264 (AVC), for upload or playback pipelines that expect AVC. 2. Watermark(imagePath: 'assets/watermark.png', alignment: WatermarkAlignment.bottomRight) adds your logo. Our docs state that no watermark is added by default. 3. Each ExportedVideo entry produces its own file, so two entries mean two encodes on the user's phone. The result carries more than video paths. ExportResult also returns previewFilePath, metaFilePath and audioMeta, and the plugin's example describes the meta file as short data used in the exported video. To play the exported file inside your own screen, the official video_player plugin is enough. Encoding time depends on the phone, so measure the export on the slowest Android model you support. Our video editor SDK performance benchmark shows how results spread across devices. Which Flutter video editor route fits your app? Video editing in Flutter has four realistic routes, and each is the right call for some team. | Question | Banuba plugin (ve_sdk_flutter 0.48.1) | Banuba integration sample | video_editor 3.0.0 | ffmpeg_kit_flutter | | :-- | :-- | :-- | :-- | :-- | | What it is | Ready editor UI behind one Dart call | Full app source using a platform channel | Dart widgets for trim, crop, rotate and cover | FFmpeg and FFprobe command runner | | Editing UI | Included, native screens | Included, editable native code | You assemble it from widgets | None | | Export | Included, mp4 or mov | Included | Builds FFmpeg commands, does not export | Any FFmpeg command you write | | Access | Trial token on request | Trial token on request | Open | Open | | License | Commercial | Commercial | MIT | LGPL 3.0 by default, some packages GPL v3.0 | | Maintenance state | Released against current native SDK versions | Tracks the plugin | Latest release is 3.0.0, no release since | Upstream FFmpegKit retired; successor and community forks exist | Four ways to read that table: - Fastest to a complete editor: the Banuba plugin. Recording, timeline, effects and export arrive behind the call in Step 4. - Most control over native behavior: the Banuba integration sample. The Flutter integration sample on GitHub ships the app source, so your team can change the native layer rather than wait for a plugin release. - Cost and UI ownership: video_editor. It is free under MIT and every widget is yours to style. You still need an export path, because its README says the library does not handle exportation. - Raw codec control: the FFmpeg route. No other option lets you write arbitrary FFmpeg commands, and the licensing is the thing to settle first, since the default build is LGPL 3.0 and some variants are GPL v3.0. The FFmpeg route needs one more sentence, because the package most guides still point at is not where the work happens now. The upstream project posted a retirement notice in July 2026 stating that FFmpegKit has been officially retired, and names FFmpegKitNext as the actively maintained continuation, distributed as source only, alongside community-maintained forks published for Android, Flutter and React Native through the usual package managers. A team going this way is picking a fork and a build process, not just adding a dependency. One more limit of our own: the Banuba editor does not run on the web, so a Flutter web target needs a different route for that platform. Why use Banuba for a Flutter video editor? Banuba Video Editor SDK covers recording, a multi-track timeline, effects, AI clipping, AI subtitles and export in one plugin. Our docs state that it works offline and does not send, store or process user information. They also publish agent skills for Claude Code, Codex and Qwen Code, plus an LLM-friendly documentation file for AI-assisted coding. It does not hand you Dart widgets to restyle line by line. The screens are native, and you shape them through FeaturesConfig, so a team that wants a pixel-level custom UI in Flutter is better served by video_editor plus its own export path. For the native side of the same editor, see our walkthrough of integrating the iOS video editor SDK in Swift. For other vendors, our comparison of five video editor SDKs for social apps puts Banuba next to the alternatives, and the original Flutter guide on our blog covers the feature list in more depth. Six steps take a Flutter app from pubspec to an exported clip Pin ve_sdk_flutter at 0.48.1, add the Podfile sources and permissions, set the Android size switches, and call one open...Screen method from a mounted widget. Then decide the export: which resolutions, which codec, and whether a watermark goes on. Check the size table in Step 3 and the four failure modes in Step 4 before the first device run. Three of them throw, and the fourth returns null and looks like a user walking away. FAQ Is the Banuba Flutter video editor free? The Banuba Flutter video editor is free for a 14-day trial with the full feature set, and the plugin's pub.dev page says no credit card information is needed. Production use needs a commercial Banuba license. Does the Banuba Flutter video editor work offline? Yes. Banuba's documentation states that the Video Editor SDK works offline and does not send, store or process user information. Does the Banuba Video Editor SDK support Flutter web? No. The Banuba Video Editor SDK runs on iOS and Android, and pub.dev lists only those two platforms for ve_sdk_flutter. How do I fix ERR_SDK_NOT_INITIALIZED in the Banuba Flutter plugin? The Banuba plugin returns ERR_SDK_NOT_INITIALIZED when the license token is empty or invalid. Check that the token reaches the call, for example that you passed --dart-define=BANUBA_TOKEN=... when you started the app. Why does openTrimmerScreen return null in the Banuba Flutter plugin? Because the new editor UI is on by default. FeaturesConfigBuilder sets enableEditorV2 to true, and the plugin blocks the trimmer entry point under it, logging "New UI is not available from Trimmer screen" and returning null rather than throwing. Call .enableEditorV2(false) on the builder if you need that screen. How much does the Banuba video editor add to a Flutter app's size? Banuba documents 25 MB on Android and 14 MB on iOS for the core editor, 45 MB for the full bundle, and 45 to 90 MB on Android or 45 to 140 MB on iOS with face AR. Turning face AR off and filtering architectures moves a build toward the core figures.

  2. project.pbxprojのコンフリクトをTuist導入で構造的になくす 私の所属している株式会社DIGITALIOでは、ポイントメディアサイトECナビを運営しており、 ECナビアンケートアプリ というモバイルアプリも展開しています。 本記事では、iOSアプリの並行開発で問題になっていた project.pbxproj のコンフリクトを、Tuist導入によって構造的になくした話をお伝えします。 tuist/tuist TL;DR 想定読者: iOSアプリの開発で project.pbxproj をGit管理している方 Tuist: Swiftで書いた定義ファイルからXcodeプロジェクトを生成するCLIツール 定義ファイルから project.pbxproj を毎回生成できるので、生成物をGit管理から除外できた project.pbxprojをGit管理することの難しさ 本アプリは、複数人で並行開発を行っています。Xcodeプロジェクトの実体は ECNaviEnqueteApp.xcodeproj/project.pbxproj という単一のテキストファイルです。ファイルの追加や設定変更のたびに、Xcode経由でこれを書き換える必要がありました。 私たちのチームは project.pbxproj をGit管理していたため、複数のブランチで同時にファイル追加や設定変更が発生すると、このファイルはコンフリクトしました。特に並行開発が増えた時期には、複数の行にまたがるコンフリクトの解消に手間がかかっていました。 PR1「project.pbxprojにファイルを追加してmasterにマージした!」 PR2「project.pbxprojにファイルを追加してmasterにマージするぞ!」 │ ▼ _人人人人人人人人人_ >  コンフリクト!! <  ̄Y^Y^Y^Y^Y^Y^Y^Y^ ̄ <<<<<<< HEAD (PR1がpbxprojに追加した内容) ======= (PR2がpbxprojに追加した内容) >>>>>>> PR2 (;´Д`) 手作業でdiffを解読するしかない… また、実装ファイルだけをXcodeプロジェクトに追加し、テストファイルの追加を忘れることもありました。ビルドターゲットに含まれないテストは実行されず、CIも通るため、マージ後に追加漏れが発覚します。 これらの問題に加えて、Xcode上のGUI操作でプロジェクトを管理する方式には、次の2つの課題もありました。 設定変更がXcode上のGUI操作に依存するため、手順が煩雑になる project.pbxproj は人間にもAIエージェントにも読み解きにくく、変更の意図を追いにくい これらの課題を根本からなくすため、定義ファイルから project.pbxproj をCLIで自動生成する運用への切り替えを検討しました。生成物をGit管理から除外できるため、 project.pbxproj に起因するPR間のコンフリクトをなくせます。 XcodeGen・Tuist・Bazelの比較 プロジェクト生成ツールとして候補に挙がったのはXcodeGen・Tuist・Bazelの3つです。選ぶ条件は次の3つでした。 定義ファイルの誤りを、型とコンパイラで防げる 既存のCocoaPods運用を維持したまま導入できる 既存のビルドシステムを置き換えない この条件で各ツールを比較しました。 観点 XcodeGen Tuist Bazel 定義形式 YAML Swift DSL Starlark 定義ファイルの型検査1 なし あり なし CocoaPods互換性2 ○ ○ △ ビルドシステムの置き換え なし なし あり 結果、Tuistを導入することにしました。TuistはSwiftで記述できるため、引数の型や構文の誤りを定義ファイルのコンパイル時に検出できます。 XcodeGenは、YAMLゆえの型安全性の低さが気になりました。Bazelはリモートキャッシュや再現可能なビルドの面で強力な一方、Xcodeのビルドシステムごと置き換える規模感が今回の目的には釣り合わないと判断しました。 ! 選定後に知ったことですが、XcodeGenとTuistはどちらも tuist/XcodeProj を利用しています。Xcodeプロジェクトの読み書きを担う層は共通のため、この層に限れば、どちらを選んでも継続性の懸念は小さいと考えています。 Tuist導入の進め方 導入は影響範囲を絞るため3段階のPRに分割しました。 miseによるツールのバージョン固定 miseは、Node.jsのnvmやasdfのように、ツールのバージョンをプロジェクト単位で固定できるツールです。 mise.jdx.dev Tuistはインストール方法にmiseを推奨している3ため、本アプリでもバージョン固定にmiseを採用しました。 まずは .mise.toml を導入し、開発者間でTuistのバージョン差異が生じないようにしました。CIでも jdx/mise-action を使い、ローカルと同じバージョンのTuistを利用しています。 [tools] tuist = "4.195.9" Project.swiftの定義とMakefile整備 次に、定義ファイルの追加と便利コマンドの整備を行い、自動生成の運用フローを整えました。 Project.swift 既存のビルドターゲット・スキーム・ビルドスクリプトを Project.swift で再現し、従来と同等のビルド動作を維持しました。 import ProjectDescription private let appDependencies: [TargetDependency] = [ .sdk(name: "AdSupport", type: .framework, status: .optional), ] private let appTarget = Target.target( name: "ECNaviEnqueteApp", destinations: .iOS, product: .app, deploymentTargets: .iOS("15.0"), sources: [ .glob( "ECNaviEnqueteApp/", // ... ), ], resources: [ "PrivacyInfo.xcprivacy", .glob(pattern: "ECNaviEnqueteApp/", excluding: commonResourceExclusions), ], dependencies: appDependencies, // ... ) let project = Project( name: "ECNaviEnqueteApp", targets: [appTarget, appDevTarget, testsTarget, previewTarget], schemes: [appScheme, appDevScheme, previewScheme, testsScheme], // ... ) ビルドターゲットのファイルはglobで指定するため、ファイルを追加しても定義ファイルの編集は不要です。 CocoaPodsの統合方法 本アプリは当時CocoaPodsで依存関係を管理しており、 pod install が生成済みのXcodeプロジェクトへビルドフェーズやxcconfig参照を書き込む構成でした。そのため、 tuist generate から pod install までを一括で実行する make sync-develop 等を Makefile に用意しました。ここで地味にハマったのが、 pod install の挙動です。 sync-develop: 環境ごとに差し替えるファイルを事前にコピー cp ECNaviEnqueteApp/Resource/GoogleService-Info-Develop.plist ECNaviEnqueteApp/Resource/GoogleService-Info.plist Xcodeプロジェクト生成と依存関係の解決 tuist generate --no-open bundle exec pod install CocoaPodsには、依存関係に変更がなければ、変更のないPodのターゲットの再生成とプロジェクトへの統合を省略する 「インクリメンタルインストール」 (Incremental Pod Installation)があります。この仕組みは、 Pods/.project_cache/ に保存した前回のキャッシュキーと、今回の依存関係やビルド設定から作ったキャッシュキーを比べて変更の有無を判断します。このときアプリ側のXcodeプロジェクトの状態は見ません4。本アプリの Podfile では、当初 :incremental_installation => true を指定して有効にしていました。 install! 'cocoapods', :generate_multiple_pod_projects => true, :incremental_installation => true ... 一方、Tuistは tuist generate のたびにXcodeプロジェクトを完全に再生成するため、直前にCocoaPodsが追加したビルドフェーズやxcconfig参照は消えます。 tuist generate 直後の pod install では、 Pods/ 側のキャッシュが残っているため変更なしと判断され、ビルドフェーズやxcconfig参照が書き込まれませんでした5。原因はインクリメンタルインストールの差分判定にあったため、 :incremental_installation => false で無効化したところ、毎回書き込まれるようになりました。 ! 何らかの理由でインクリメンタルインストールを true のまま維持する場合は、 bundle exec pod install --clean-install で同様に統合できます。 project.pbxprojなどをGit管理から除外 第2段階でプロジェクト生成が安定して行えることを確認できたため、最後に ECNaviEnqueteApp.xcodeproj/ と ECNaviEnqueteApp.xcworkspace/ を git rm --cached でGit管理から除外しました。 Tuist Derived/ ECNaviEnqueteApp.xcodeproj/ ECNaviEnqueteApp.xcworkspace/ これにより project.pbxproj に起因するコンフリクトは発生しなくなりました。 Project.swift の同時編集によるコンフリクトは残りますが、読みやすいSwiftファイルの差分になります。生成物が手元に存在しない状態になるため、チームへの周知とドキュメント整備も合わせて行いました。 環境構築手順をまとめた docs/setup.md に、プロジェクト生成と依存関係のインストールの手順を追加した AIエージェント向けの CLAUDE.md に、 make sync-develop が必要になるタイミングとコマンドを記載した ドキュメントの記載例## プロジェクト生成と依存関係のインストール ECNaviEnqueteApp.xcodeproj/ と ECNaviEnqueteApp.xcworkspace/ はTuistによって自動生成されるためGit管理から除外されており、以下のコマンドによって管理している。 | コマンド | 用途 | | --- | --- | | make sync-develop | 開発用の GoogleService-Info.plist を配置し、Tuistでプロジェクトを生成、CocoaPodsを統合する | | make sync-release | 本番用の GoogleService-Info.plist を配置し、Tuistでプロジェクトを生成、CocoaPodsを統合する | 以下のケースで make sync-develop の実行が必要: - git clone の直後 - git pull やブランチ切り替え( Project.swift やファイル構成に差分がある場合) - 依存関係の更新 - ファイルの追加・削除 make init は内部で sync-develop を呼び出すため、初回セットアップ時は make init を実行するだけでよい。 Xcodeを開いた状態で sync-* を実行した場合 Xcodeでプロジェクトを開いたまま make sync-* を実行すると、Xcodeプロジェクトが外部から書き換えられたことをXcodeが検知し、ダイアログが表示される。 「Use Version on Disk」を選択する。 make sync-* によって生成された最新のファイルがXcodeに反映される。 導入後の変化 記事の前半で挙げた4つの課題は、次のように変わりました。 課題 導入後 PR間のコンフリクト project.pbxproj 起因はなくなった ファイルの追加漏れ sources のglobに一任 GUI操作の煩雑さ Project.swift の編集と make sync-develop で完結 解読の容易性 定義ファイルの差分として追えるようになった 一方で、トレードオフもあります。 git clone 直後のほか、ブランチの切り替え、ファイルの追加・削除、依存関係の更新のたびに make sync-develop の実行が必要になりました。 また、実行のたびにXcodeプロジェクトを再生成する関係上、次の2点にも注意が必要になりました。 一時的に有効にしたい設定はXcode上のGUI操作で変更しますが、プロジェクトの再生成時に失われます。例えば、デバッグ用に追加した FIRDebugEnabled などの起動引数です。 Xcodeを開いたまま実行すると「The file "..." has been modified by another application」というダイアログが出ます。そのため、その都度Xcodeを再読み込みし、ディスク上の最新状態を反映する運用にしました。 コンフリクトの解消は内容を読み解く判断が必要でしたが、CLIで再生成する場合の結果は定義ファイルだけで決まり、失敗しても再実行で同じ状態に戻せます。この性質の違いから許容できると判断し、コマンドを Makefile にまとめ、手順をドキュメントに残しました。 まとめ project.pbxproj に起因するコンフリクトは、Tuist導入によって構造的になくせました。第1段階〜第3段階という小さなステップに分けたことで、各PRのレビューと動作確認の負荷を抑えられたのも良かった点です。 同様の課題を抱えている場合は、まず1つのビルドターゲットを Project.swift で再現し、生成物が既存の project.pbxproj と同等になることを確認してからGit管理から除外するのがおすすめです。除外した後は自動生成が通常の運用フローになるため、周知も忘れずに行いましょう。 脚注 ここでの型検査は、定義ファイルの型の誤りをコンパイル時に検出できることを指す。XcodeGenのYAMLとBazelのStarlarkは静的型を持たず、誤りは生成や評価の実行時に分かる。 ↩︎ XcodeGenとTuistはCocoaPodsを管理せず、プロジェクト生成後に pod install を実行して併用。Bazelには公式のCocoaPods統合がなく、 rules_ios やサードパーティ製のツールを使うか、Podごとにビルド設定やリソースの扱いを調整する必要がある。 ↩︎ Install Tuist · Guides · Tuist を参照。 ↩︎ 判定ロジックは project_cache_analyzer.rb と target_cache_key.rb にある。設計の背景は Phase 1 、 Phase 2 を参照。 ↩︎ Pods/.project_cache を退避すると統合が復活し、 Manifest.lock や Podfile.lock を退避しても復活しないことをCocoaPods 1.16.2で確認している。 ↩︎

Achievements

Awards earned by the repositories CocoaPods owns. Select an award to embed its badge.

Gold
1971st place finishes
Silver
1112nd place finishes
Bronze
663rd place finishes
Awarded repositories
2Owned by CocoaPods now

Repositories

Ordered by gold, then silver, then bronze.

  1. SpecsBest: 1st by PR authors, 227 PR authors19611166
  2. CocoaPodsBest: 1st by stars, 142 stars100

Every award

Top-three finishes of these repositories in completed trending days and weeks, newest first.

  1. Specs
  2. Specs
  3. Specs
  4. Specs
  5. Specs
  6. Specs
  7. Specs
  8. Specs

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.