2025年、iPhoneで自分の音楽を再生することは驚くほど困難で、Appleに支払わないか、あるいは制限の迷路を移動しないかぎり、私は完全なテキスト検索、iCloudのサポート、およびローカルファースト・エクスペリエンスを備えた自分のプレーヤーをゼロから構築しました。
2025年、iPhoneで自分の音楽を再生することは驚くほど困難で、Appleに支払わないか、あるいは制限の迷路を移動しないかぎり、私は完全なテキスト検索、iCloudのサポート、およびローカルファースト・エクスペリエンスを備えた自分のプレーヤーをゼロから構築しました。
なぜ自分のオーディオプレーヤーを作ったのか
多くの人と同様に、私はApple(iCloud、Apple Music)を通じて多くのサブスクリプションを取得しましたが、他のサブスクリプションはランダムなプラットフォーム(Netflixのように、私はまだ支払いを忘れていました)で失われました。
最初は、iCloud Music Library を使い続けるつもりだったのですが、Apple Music サブスクリプションをキャンセルすると、同期が止まりました。behind a paywallテクニカルで返すことができます。iTunes 試合(年間 24.99 ドル). Match only stores 256-kbps AAC copies online; your original files stay put unless you choose to replace them. On a modern Mac, you do all this in the Music app. サブスクリプションなしでは、クラウド同期がなくなり、ケーブル/Wi-Fi同期に戻ります。
iTunes 試合選択肢の欠如に挫折した私は、builder routeもし私がコンピューティングデバイス(この場合のiPhone)を購入した場合、何が私がコードで使うために必要なものだけを構築するのを止めているのでしょうか? この記事では、基本的な音楽プレーヤー機能を作成するための私の完全な挫折の旅を共有したいと思います:オーディオファイルをロードし、それらを整理し、再生しますが、主に、私は自分自身を思い出させたいと思います。これはまだ一般的な用途のコンピュータで、私はそれをやりたいことをできるはずです。.
Apple(およびその他)が今日提供するもの
私自身のアプリを作成する前に、オフライン音楽再生の公式および第三者オプションを探索しました。
Apple's Built-in Apps について
Apple は、技術的には、Files アプリを通じて iCloud から音楽を直接再生できますが、その機能は音楽を聴くために設計されていません。lacks essential featuresプレーリストの管理、メタデータの分類、または再生列など、音楽の再生をサポートしますが、非常に制限され、全体的に良いユーザー体験がありません。.
良いユーザー体験がありません。第三者アプリ
私はアプリストアに行き、私の問題を解決するクールなアプリを探しましたが、それらの多くは、多くの人が頼っています。subscription-based pricing, すでに所有しているユーザーのファイルを再生するアプリの疑わしいモデル. There is one app that I liked,ドップラー. 私は試用中にそれをプレイしましたが、UXはアルバムを管理するために構築されています. 検索はそれほど良くなかったし、iCloudからのインポート機能は、大量の埋め込まれたフォルダで使用するのが遅く、困難でした. 反対側は、単一の支払い価格モデルを持っていました。
「Going Builder Mode: My Technical Journey」
それを言って、私は私の痛みの点を解決する自分の理想の音楽プレーヤーを作成することにしました。
- iCloud フォルダを介して柔軟なフルテキスト検索で、音楽や特定のファイルを含むフォルダを迅速に選択してインポートできます。
- 音楽を管理する機能は、少なくとも公式の音楽アプリと同様に機能します:列、プレーリスト管理、アルバムによる分類など。
- 親しみやすいインターフェイス。
ネイティブファースト React Native First
数年前、私はシンタクス(TypeScriptに近い感じ)が好きで、Rustのようなメモリのセキュリティを評価しましたが、ネイティブではありませんでした。async
/await
当時、GoやJS/TSに比べて同時にコードを書くことは、つまらないし、ボイラープレートが重いと感じたので、このプロジェクトを再訪したとき、最初はもっと馴染みのあるものを求めました。
言い換えれば、私はReact NativeまたはExpoで、私のWeb開発経験を再利用し、既存のテンプレートからプレイヤーUIを接続することを望んでいました。再生UIの構築はシンプルでした。タイトル: Template Project by Gionatha Sturbaなぜなら、私のアプリに必要なすべての機能を持っているように見えたからです。
ファイルシステムへのアクセスとクラウドファイルの同期は、主要なブロックに直面します: library likeexpo-filesystem
基本的なファイルの選択をサポートしますが、深く埋め込まれたiCloudディレクトリを回復して移動します。often failed or even caused app crashesこれにより、AがJavaScript-based approach introduced more complexity単にAppleのネイティブAPIと作業するよりも、それはより急激な学習曲線を意味していたとしても。
iOS サンドボックスは、アプリがユーザーの明示的な許可なしにファイルを読み取ることができなくなり、React Native は外部のフォルダに信頼できるようにアクセスできませんでした。
SwiftUIへの切り替え
I went withSwiftUIUIKitやストーリーボードの代わりに、私が望んだのは、clean and declarative UIドメインロジクスとデータ同期に焦点を当てている間、その方法から抜け出すようなレイヤーです。 async/await や integration withSwift ActorsSwiftUI はまた、アプリケーションを孤立した ViewModel コンポーネントに構築するのを容易にし、OpenAI o1 および DeepSeek のような LLM からより良い結果を得るのに役立ちました。
アプリ・アーキテクチャとデータ・モデル
私が作成したアプリケーションのアーキテクチャについて考えてみましょう:私は持続的なデータストレージのためにSQLiteを使用し、アプリケーションアーキテクチャをシンプルなサーバーアプリケーションとしてアプローチしました. CoreDataを避けたのは、スケジュール、サウンドクエリ、特にフルテキスト検索の厳しい制御が必要だったためです. SQLiteの組み込まれたFTS5サポートにより、外部検索エンジンを重く引っ張ったり、独自のインデックスレイヤーを構築したりすることなく、速く曖昧な検索を追加できます。
3 主なスクリーン
The app consists of 3 screen/modes:
- 図書館の輸入. これがあなたのiCloud図書館フォルダを追加する場所です. アプリはオーディオファイルのためのすべてのフォルダをスキャンし、SQLiteデータベースにすべてのパスを挿入します. この方法で、あなたは検索、フォルダの追加、およびサブフォルダの完全な柔軟性を持ることができます. Appleのネイティブファイルピクヤーは非常にクローンキーです. あなたはキーワードで検索した複数のディレクトリを選択することはできません. それは単にそれを行うために設計されていません。
- 図書館管理. これが追加された曲を管理し、再生リストを整理できる場所です. ほとんどの場合、私はAppleが音楽アプリでそれをやった方法を反映し、私のニーズに十分に適していました。
- プレーヤーと再生 アプリケーションのこの部分は、列の管理 (repeat、shuffle) など、再生、停止、および次の曲の機能を管理します。
シンプルなユーザフロー・ダイアグラムは、ここに示されています。
User flow in practice:アプリケーションが空のライブラリで起動すると、Sync タブに到着し、大きな「iCloud Source を追加」ボタンを表示します。そこにフォルダを選択し、Sync 画面は、木を歩いている間に進捗バーを表示します。Playlists / Artists / Albums / Songsすべてのリストに潜り、トラックをタップし、ミニプレーヤーが底部に表示されます。そのミニバーをタップして、フルスクリーンプレーヤーをシャフル、繰り返し、列のリオーダー、およびボリュームで開きます。スワイプまたは閉じるアイコンをタップし、再生が続く間にライブラリに直ぐに戻ります。 あなたがより多くの音楽を必要とするたびに、Syncに戻り、ナブバーの「+」をタップし、別のフォルダを選択し、インポートサービスは背景に新しい曲を合併し、再起動は必要ありません。
Backend-Like Logic Layer
ウェブ / クラウドの背景を持って、スタートアップで働く間に多くのサーバーコードを配信した私は、backend-like architectureモバイル アプリで、ドメイン/ロジック レイヤー全体が、View and View-Model layerBecause I had to nail thecloud syncing, metadata parsingアプリの側面と、SQLite DBへのクリーンデータアクセスを有する。以下は、私がここで使用した約層建築図です。:
How the layers talk:SQLite は底部に位置し、原曲の行と FTS インデックスを格納します。その後、リポジトリはデータベースを包み込み、アシンク API を露出します。domain actorsすべてのビジネスルール(輸入、検索、列の論理)を所有するスウィフト俳優で、状態変異が残るthread-safeViewModels は俳優にサブスクリプトし、データを UI 準備の構造に変換し、SwiftUI ビューは彼らが得るものを単に再生します。nicely decoupled.
Full Text Search を SQLite で実装する
前述したように、FTS機能を持つSQLiteのバージョンをインポートできるのは幸運です:iOS 11から始めて、ボックスから入手できます。without extra setupこれにより、Fuzzy Search を音楽ライブラリに組み込むことが容易になりました。without any third-party dependenciesさらに、通常のクエリのために SQLite.swift ライブラリを使用しました(コンパイル タイム セキュリティを備えたクエリ ビューダーとして機能します)、しかし、FTS クエリでは、通常の SQL 文を参照しなければなりませんでした。
SQLiteのFTS5この拡張機能は、アーティスト、アルバム、タイトルなどのファイル名やメタデータを追加のインデックスインフラストラクチャなしでクエリすることができます。
FTS Tablesの設定
Domain |
Swift actor / repo |
FTS5 table |
Columns that get indexed |
---|---|---|---|
Library songs |
|
|
|
Source-browser paths |
|
|
|
図書館歌
SQLiteSongRepository
songs_fts
artist
で、title
で、album
で、albumArtist
Source-Browser パス
SQLiteSourcePathSearchRepository
source_paths_fts
fullPath
で、fileName
FTS5の2つのテーブルを使用しました: 1つはインデックスされた曲(アーティスト/タイトル/アルバム)と1つはフォルダーのインポート中にファイルパスです。songs
で、source_paths
FTSはread-only for the UIすべての書き込みは、リポジトリの内部で起こりますので、何も裂け穴を通って滑らないのです。
検索インデックスの作成
SQLite の組み込みの FTS5 は、迅速な検索を容易にします. Here is a simple table definition I used:
try db.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
songId UNINDEXED,
artist, title, album, albumArtist,
tokenize='unicode61'
);
""")
I 使用unicode61
tokenizer は、幅広い種類の文字が処理されることを保証します。Non-searchable keys are flagged withUNINDEXED
だから言葉の辞書を吹き飛ばさない。
信頼性の高いデータ更新
物事をシンプルで安全に保つために、私はアップデートを包装し、トランザクションに挿入します。これにより、アプリが崩壊したり中断されたとしても、検索インデックスは決して同期されません。
func upsertSong(_ song: Song) async throws {
db.transaction {
// insert or update main song data
// insert or update search index data
}
}
「Fuzzy Search」
ユーザーフレンドリーな検索のために、私は自動的にワイルドカードのサポートを追加します. あなたが "lumine" を入力すると、内部で "lumine*" を検索し、部分的なクエリでさえすぐに結果を提供します。
スピリチュアルなスピリチュアルなスピリチュアルなスピリチュアルなスピリチュアル(bm25
) 追加の複雑さなしにより関連する結果を返す:
SELECT s.*
FROM songs s JOIN songs_fts fts ON s.id = fts.songId
WHERE songs_fts MATCH ?
ORDER BY bm25(songs_fts)
LIMIT ? OFFSET ?;
全体として、原始SQLiteを使用すると、予測可能なスケジュール、ローカルファーストアクセス、および強力なフルテキスト検索、ネットワーク依存や外部サービスを導入することなく、必要な柔軟性を提供しました。
iOS ファイルとブックマークの作業
iOS では、アプリはファイルの場所に持続的なブックマークを保存できますが、security-scoped bookmarksアプリのサンドボックス以外のファイルへの拡張アクセスを許可するアプリは、macOSiOS アプリケーションでは、通常のブックマークを使用してファイルパスを記憶し、ドキュメント ピクヤーを介して再度アクセスを要求できますが、そのアクセスが静かに続く保証はありません。Appleのブックマーク文書.
これを軽減するために、私はファイルをファイルにコピーするバックバックメカニズムを実装しました。app's own sandboxed containerこれにより、iOS が許可をリセットする場合に静かに破られるセキュリティに影響を与えるブックマークの脆弱なライフサイクルを回避できます。 ブックマークが有効である間、ファイルを背景に積極的にコピーすることにより、無効なオーディオファイル参照にアクセスするリスクはありません。
このアプローチはまた、インデックス速度を向上させます. I can scan the folder structure once (while access is active), import only relevant audio files, and safely traverse deeply nested directories. But reliably playing back individual audio files from external locations, especially after device restarts. このアプローチは、フォルダーの構造を1回スキャンすることができます。私にとって未解決の問題です。これは、どのようにunder-supportedこの使用例は、ネイティブのアプリでも、それがどれほど複雑であるかhandle file access reliably on iOS.
プレイバックとUIの構築
メタデータパルシング
オーディオファイルからメタデータを解析するには、AppleのAVFoundation framework特に、TheAVURLAssetタイトル、アルバムアーティストなどのメディアファイルメタデータの検査を可能にするクラスですが、メタデータの解析はネイティブSDKによって処理されますが、トラック番号のような特定のフィールドはID3タグから手動で検索する必要があります。GitHub検索例を見つけるため、公式文書にはエッジケースのカバーが欠けていた。
AVFoundationによるオーディオ再生
ライブラリがインデックスされた後、オーディオプレーヤーの実装は非常にシンプルに感じます:あなたは単にインスタンスを初期化する必要があります。AVAudioPlayer
さらに、生活の質の機能のために:コントロールセンターから音楽を再生するために、私はコントロールセンターを実装する必要がありました。AVAudioPlayerDelegate
プロトコルおよびAppleのプロトコルにハックされたMPRemoteCommandCenter
開発者がシステムレベルの再生コントロールに対応できるようにします。
Apple、Developer Lock-In、そして未来
開発中に突出したもの: Here is what stood out during development:
THE BAD
Xcode's limitations remain frustrating.リアルタイムのSwiftUIのプレビューは確実に一歩前進するが、全体的な開発経験はFlutterが5年前に提供したものと同等ではない:緊密なVSCode統合、リアルタイムのシミュレータリロード、および既知のデバッグツール。
Lack of editor flexibility.Neovim または VSCode で Swift の Language Server Protocol (LSP) サポートを設定するには、追加のツールが必要です。xcode-build-server
なお、Web ファースト エコシステムの開発者の経験と完全に一致していない。
Some corners of Apple's SDK still live in Objective-C land.たとえば、Spotlightファイルの検索は、NSMetadataQuery
Key-Value Observing (KVO) と string keys を使用して、まだ Swift-friendly wrapper はありません. Documentation is often scarce, which steeps the learning curve. ドキュメンタリーはしばしば希少です。
SwiftUI's declarative UI is great, but debugging iCloud interactions still requires manual mocks.SwiftUIのプレビューは、iCloudの権限を含む完全なアプリの行動を模することはできませんので、小さいが顕著な不快感で、マニュアルでクラウドの相互作用を嘲笑しなければなりません。
THE GOOD
Async/await.最後に、私は不快なコールバックなしで必然的なコードのようにI/O-bound同期コードを書くことができます. That's a big win, and I greatly appreciate how easy it is to write even sync code into Actors and call it like you do in JavaScript ecosystems.
Plethora of native libs.はい、あなたはReact Native/Flutterエコシステムのようなオープンソースの結びつきによって制限されていません ここでは、あなたの会社/製品のウェブサイトの置き換えよりも「より深刻な」何かを開発するよりはるかに自由があります(モバイルファーストの経験が悪いため)。
SwiftUIはい、ReactスタイルのUIを構築するアプローチは、より多くの生産性と探索のためのスペースを提供します。
タグ : 建物が楽になる
ハッキングの 1.5 週間後、私は私のニーズを正確に満たすソフトウェアを手に入れることができました。local/offline music playerクラウドストレージからオーディオファイルをインポートできます。
しかし、開発者は今日、自分のデバイスにアプリを簡単にデプロイすることはできず、それを忘れてしまいます:アプリは単に実行されます。DEV証明書なしの7日間その後、開発プログラムに登録するためにAppleに99ドルを支払わなければ、再構築しなければなりません。
DEV証明書なしの7日間たとえその後のDMA Act in the EUEUユーザーは現在、開発者のサイトから直接第三者市場のアプリをインストールできますが、その開発者がまだAppleの99ドル/年間プログラムに登録し、Appleの代替条件に同意している場合にのみ。
革新的なテクノロジー企業は、民主化されたアプリケーション開発に積極的にブロックを与えています。iOS での注目すべき制限: Apple の 16-18.x アップデートの後でさえ、iOS PWAs は Safari のサンドボックス内でまだ実行されています. They get WebGL2 and web-push, but they don't get Web Bluetooth/USB/NFC, Background Sync, or more than ~50MB of guaranteed storage. WebGL runs through Metal shim, so real-world frame rates often trail native Metal apps; this is good enough for UI, but not for AAA 3D games.
今日では、AIは、誰でもアクセス可能な方法で必要なすべての知識を提供することによって未知のテクノロジーに対処することを可能にすることによって、現代のソフトウェア開発の複雑さを減らしてきました。Web開発は、多くのテクノロジーに特化することなくアイデアを構築する方法を持っている非技術的な人々からどのように関心を得ているかをはっきりと見ることができます。たとえあなたがそれを自分で作ったとしても、あなた自身のために、Appleはまだ最後の言葉を得ます。かつて独立した開発者に権限を与えた同じ会社が今、tight restrictions that hinder personal app developmentAIは、ゲートがまだロックされているiOS向けに構築していない限り、これまで以上に新しいツールを構築することを容易にしました。
関連リンク
- iTunes Match - Apple サポート
- セキュリティスコープブックマーク - Apple Docs
- FTS5 - SQLite ドキュメント
- ミュージックプレーヤー - App Store
- EXPO FileSystem ドキュメント
- Apple Developer Program Info (7 日間のビルド)
- Apple コミュニティ:Files App & MP3 Playback