Trình phát audio do chính tôi tự làm
(nexo.sh)- Ngay cả vào năm 2025, việc phát nhạc MP3 tự sở hữu một cách tự do trên iPhone vẫn còn nhiều hạn chế
- Apple và các ứng dụng bên thứ ba phần lớn либо là dịch vụ trả phí, либо thiếu tính tiện dụng cho người dùng
- Ứng dụng tự phát triển cung cấp tìm kiếm toàn văn, hỗ trợ iCloud, môi trường ưu tiên cục bộ v.v.
- Cách tiếp cận đa nền tảng như React Native có giới hạn do ràng buộc hệ thống tệp và vấn đề ổn định
- Với thiết kế dựa trên SwiftUI và SQLite, ứng dụng hiện thực hóa trải nghiệm quản lý nhạc độc lập và có khả năng mở rộng cao
Tổng quan
Để tự mình giải quyết sự bất tiện rằng ngay cả năm 2025, người dùng vẫn khó phát tự do các tệp MP3 do chính họ sở hữu trên iPhone, tác giả đã tự xây dựng một ứng dụng phát nhạc và giới thiệu quá trình cùng kết quả. Trong khi dịch vụ âm nhạc của Apple và các ứng dụng bên ngoài đều có nhiều giới hạn và mô hình thu phí, ứng dụng do tác giả tự triển khai mang lại trải nghiệm được tối ưu cho việc quản lý và phát các tệp nhạc của người dùng.
Vì sao tôi tự làm trình phát nhạc
- Các tính năng đồng bộ hóa dựa trên đám mây như Apple Music và iCloud Music Library chỉ hoạt động khi đăng ký dịch vụ trả phí
- Khi ngừng thuê bao, đồng bộ tự động và quyền truy cập thư mục nhạc đều bị chặn hoàn toàn
- Tác giả cảm nhận rõ sự thiếu vắng quyền làm chủ đối với việc tích hợp thư viện nhạc hiện có và khả năng tận dụng thiết bị đa dụng
- Mục tiêu là hiện thực hóa quyền tự quyết rằng “với chiếc smartphone đã mua, mình cũng có thể tự làm ra các tính năng thật sự cần thiết”
Phân tích các giải pháp phát nhạc của Apple và bên thứ ba
Ứng dụng mặc định của Apple
- Có thể dùng ứng dụng Files để phát tệp nhạc trong thư mục iCloud, nhưng các chức năng cơ bản như quản lý playlist, sắp xếp metadata, thao tác hàng chờ còn rất thiếu
- Trải nghiệm người dùng không được tối ưu cho việc nghe nhạc
Ứng dụng bên thứ ba
- App Store có nhiều ứng dụng ngoài, nhưng nhiều ứng dụng dùng mô hình tính phí theo thuê bao, và mức độ tính năng cũng khác nhau
- Có một số ứng dụng trả phí mua đứt như Doppler, nhưng trải nghiệm tìm kiếm và import trong các thư mục iCloud lớn chưa mượt mà
Hành trình kỹ thuật tiến tới “builder mode”
- Tác giả quyết định phải tự làm một ứng dụng phát nhạc
- Các tính năng yêu cầu: tìm kiếm toàn văn nhanh trên toàn bộ thư mục iCloud, các chức năng quản lý nhạc ở mức ứng dụng nghe nhạc chính thức (queue, playlist, sắp xếp, v.v.) cùng giao diện trực quan
Thử nghiệm đầu tiên với React Native
- Do từng thấy bất tiện khi dùng Swift (trước đây chẳng hạn chưa hỗ trợ async/await), tác giả ưu tiên React Native/Expo
- Việc làm UI khá ổn nhờ tận dụng template mã nguồn mở, nhưng khi xử lý truy cập hệ thống tệp (thư mục iCloud) và đồng bộ hóa, ứng dụng gặp crash và bộc lộ giới hạn chức năng
- Sau khi nhận ra rằng theo chính sách sandbox của iOS, không thể truy cập thư mục ngoài nếu không có quyền rõ ràng, tác giả đã chuyển sang Swift
Lựa chọn SwiftUI và lý do
- Tận dụng mô hình UI khai báo của SwiftUI cùng async/await hiện đại và Swift Actor
- Nhờ tách biệt triệt để UI và logic dữ liệu, có thể hiện thực luồng dữ liệu sạch và xử lý đồng thời ở tầng domain
- Cũng tối ưu cho việc tận dụng LLM (OpenAI o1, DeepSeek, v.v.), giúp giảm phụ thuộc trong mã UI được sinh ra
Kiến trúc ứng dụng và mô hình dữ liệu
-
Sử dụng SQLite làm kho dữ liệu; vì có thể dùng ngay tìm kiếm toàn văn (FTS5) nên được chọn thay cho CoreData
-
3 màn hình/chế độ chính của ứng dụng:
- Import thư viện: lưu hàng loạt đường dẫn tệp audio theo từng thư mục iCloud vào DB để hỗ trợ tìm kiếm/quản lý linh hoạt
- Quản lý thư viện: playlist, phân loại bài hát, chỉnh sửa, v.v.
- Phát nhạc: quản lý queue (lặp lại, shuffle, v.v.) và điều khiển bài hát cơ bản
-
Luồng người dùng khi import thư viện:
- Từ trạng thái trống ban đầu, chọn thư mục qua "Add iCloud Source" và quét cây thư mục
- Khi lập chỉ mục hoàn tất, chuyển sang tab thư viện, nơi có danh sách theo từ khóa và mini player
- Khi thêm bài hát mới, dữ liệu được tự động hợp nhất trong nền
Tầng logic kiểu backend
- Dựa trên kinh nghiệm phát triển startup web/cloud, tác giả tách biệt triệt để tầng logic với UI/ViewModel
- Tầng domain (Swift actors) giữ các business logic chính như import, tìm kiếm, queue, qua đó đảm bảo an toàn luồng
- Việc cập nhật UI được phân tách gọn gàng thông qua ViewModel, giảm tối đa sự phụ thuộc giữa đồng bộ tệp, phát nhạc và UI để cải thiện khả năng bảo trì
Triển khai tìm kiếm toàn văn bằng SQLite
- Từ iOS 11 trở lên có thể dùng SQLite hỗ trợ FTS5 mà không cần cấu hình riêng
- Hỗ trợ tìm kiếm nhanh mà không cần chỉ mục hoặc máy chủ tìm kiếm bên ngoài
- Dùng thư viện SQLite.swift để xử lý truy vấn thông thường, còn truy vấn FTS thì viết SQL trực tiếp
Cấu trúc bảng FTS
songs_fts: lập chỉ mục các trường artist, title, album, albumArtist của bài hátsource_paths_fts: lập chỉ mục đường dẫn tệp và tên tệp- Tồn tại song song với bảng chính, và ở UI chỉ dùng cho tìm kiếm (READ)
- Việc cập nhật chỉ mục được xử lý bằng transaction DB để duy trì tính nhất quán dữ liệu
Tìm kiếm mờ (Fuzzy) và xếp hạng
- Tự động thêm wildcard vào sau giá trị nhập, sắp xếp theo độ liên quan dựa trên BM25
- Tổng thể, ứng dụng hiện thực hóa cấu trúc dữ liệu có thể dự đoán được, không phụ thuộc mạng cùng môi trường tìm kiếm cục bộ mạnh mẽ
Hệ thống tệp iOS và việc tận dụng bookmark
- Khác với macOS, iOS không hỗ trợ security-scoped bookmarks, nên thiếu khả năng duy trì truy cập mở rộng tới tệp bên ngoài
- Vì chỉ lưu thông tin đường dẫn, khi truy cập lại người dùng phải cấp quyền lần nữa
- Giải pháp là: tại thời điểm được cấp quyền, sao chép chính tệp đó vào sandbox của ứng dụng
- Việc sao chép tự động trong nền cũng cải thiện tốc độ lập chỉ mục tệp
- Dù sau khi thiết bị khởi động lại, việc phát trực tiếp tệp bên ngoài vẫn khó khăn, điều này cho thấy các hạn chế truy cập tệp của iOS là rất nghiêm ngặt
Phát nhạc bằng AVFoundation và thiết kế giao diện
- Sử dụng framework AVFoundation và AVURLAsset để phân tích metadata của tệp audio
- Một số trường như track number được phân tích thủ công (dùng thẻ ID3)
- Để phát audio, dùng AVAudioPlayer; đồng thời triển khai MPRemoteCommandCenter và giao thức Delegate để tích hợp với Control Center
Cảm nhận sau khi phát triển và suy ngẫm về chính sách của Apple
Những điểm bất tiện
- Môi trường hạn chế của Xcode: preview thời gian thực của SwiftUI có tiến bộ, nhưng vẫn chưa bằng độ tiện của VSCode hay Flutter
- Thiếu độ linh hoạt của editor: nếu muốn dùng Swift LSP trong Neovim hoặc VSCode thì cần cấu hình thêm và độ hoàn thiện còn thấp
- Một số góc của SDK vẫn thiên về Objective-C: chẳng hạn ở phần truy vấn metadata còn thiếu API thân thiện với Swift hiện đại
- Việc debug tích hợp iCloud khá phiền: không thể triển khai đầy đủ tính năng cloud trong SwiftUI preview, nên phải tự dựng mock trực tiếp
Những điểm tích cực
- Async/await giúp việc viết mã đồng thời thiên về I/O trở nên dễ dàng hơn rõ rệt
- Thư viện native phong phú: vượt khỏi giới hạn của các binding mã nguồn mở để phát triển đa dạng tính năng hơn
- Thiết kế UI khai báo của SwiftUI: cảm nhận rõ ưu điểm kiểu React và năng suất cao
Kết luận: có lẽ việc phát triển nên dễ hơn chứ?
- Mục tiêu tạo trình phát nhạc cục bộ/offline đã đạt được sau 1,5 tuần phát triển
- Trên thực tế, việc phân phối chính ứng dụng cũng có giới hạn: nếu không có chứng chỉ nhà phát triển thì sau 7 ngày sẽ không dùng được, và cần đăng ký nhà phát triển $99/năm
- Ngay cả sau EU DMA Act, sideloading vẫn chưa được mở hoàn toàn, nên các nhà phát triển cá nhân hay làm vì sở thích vẫn tiếp tục bị ràng buộc
- PWA trên iOS cũng còn nhiều hạn chế, như không hỗ trợ các API quan trọng (Web Bluetooth/USB/NFC, Background Sync, v.v.)
- AI đã hạ thấp rào cản phát triển, nhưng riêng iOS vẫn có rào cản gia nhập cao do các quy định mang tính áp đặt
- Các hạn chế đối với nhà phát triển độc lập và quyền của người dùng vẫn còn nguyên, và tính đóng của iOS vẫn là một yếu tố cản trở đổi mới
1 bình luận
Ý kiến Hacker News