En 2025, xogar a túa propia música nun iPhone é sorprendentemente difícil, a menos que pagues a Apple ou naveges por un labirinto de limitacións.
En 2025, xogar a túa propia música nun iPhone é sorprendentemente difícil, a menos que pagues a Apple ou naveges por un labirinto de limitacións.
Por que construín o meu propio reprodutor de audio
Como moitas persoas, recollín demasiadas subscricións, algunhas a través de Apple (iCloud, Apple Music), outras perdéronse en plataformas aleatorias (como Netflix, que esquecín que aínda estaba pagando).
Inicialmente pensei, eu só seguiría usando a Biblioteca de música de iCloud para a sincronización de música entre dispositivos, pero unha vez que cancelou a subscrición de Apple Music, a sincronización deixou de funcionar.behind a paywallTecnicamente pódese recuperar a travésXogos de iTunes($ 24,99 ao ano)Match só almacena 256-kbps copias AAC en liña; os seus arquivos orixinais permanecen colocados a menos que decida substituílos. nun Mac moderno, fai todo isto na aplicación de música.
Xogos de iTunesfrustrado pola falta de opcións, fun aobuilder routeSe merquei un dispositivo de computación (iPhone neste caso), o que me impide construír exactamente o que necesito con código para usalo? neste artigo, quero compartir a miña viaxe completa de frustracións cara a creación dunha funcionalidade básica do reprodutor de música: cargar arquivos de audio, organizalos e reproducilos, pero sobre todo, quería lembrarme,este aínda é un ordenador de propósito xeral, eu debería ser capaz de facelo facer o que quero.
O que Apple (e outros) ofrecen hoxe
Antes de escribir a miña propia aplicación, explorei as opcións oficiais e de terceiros para a reprodución de música offline.
Aplicacións de Apple
Tecnicamente, Apple permítelle reproducir música directamente desde iCloud a través da aplicación Arquivos, pero a súa funcionalidade non está deseñada para escoitar música.lacks essential featurescomo a xestión de listas de reprodución, a clasificación de metadatos ou as filas de reprodución.Mentres soporta a reprodución de música, é moi limitada e globalNon unha boa experiencia de usuario.
Non unha boa experiencia de usuarioAplicacións de terceiros
Fun á tenda de aplicacións para buscar aplicacións cool que resolvan o meu problema, mentres que hai moitos deles, moitos dependen desubscription-based pricing, un modelo cuestionable para unha aplicación que simplemente xoga ficheiros que os usuarios xa posúen.DopplerEditarEu xoguei con el durante un ensaio, pero o UX está construído en torno á xestión de álbums. A busca non foi tan boa, e a funcionalidade de importación de iCloud foi lenta e difícil de usar nun gran número de carpetas anexadas.
Going Builder Mode: A miña viaxe técnica
Dito isto, decidín crear o meu propio reproductor de música ideal que resolva os meus puntos de dor:
- Busca flexible de texto completo en todas as carpetas de iCloud, para que poida seleccionar e importar rapidamente unha carpeta con música ou ficheiros específicos.
- Funcionalidade na xestión da música polo menos en paridade coa aplicación oficial de música: cola, xestión de listas de reprodución e clasificación por álbums, etc.
- Interface familiar e amigable.
Intentar reaccionar nativo primeiro
Algúns anos atrás, gustoume a sintaxe (sentiuse máis preto de TypeScript) e apreciou a seguridade da memoria como Rust, pero sen nativoasync
/await
Naquel momento, a escritura de código simultáneo en comparación con Go ou JS / TS sentiuse clunky e boilerplate-pesado. Esa experiencia deixoume frustrado, así que cando revisitei este proxecto, inicialmente cheguei a algo máis familiar.
Dito isto, fun con React Native ou Expo, coa esperanza de reutilizar a miña experiencia de desenvolvemento web e conectar unha interfaz de usuario do xogador a partir de modelos existentes. Construír a interfaz de usuario de reprodución foi sinxelo; hai numerosos exemplos de código aberto e vídeos de tutorial sobre a construción de xogadores de música que se adapten ás miñas necesidades.Páxina oficial de Gionatha Sturba, porque parecía ter todas as funcións que necesito para a miña aplicación.
O acceso ao sistema de ficheiros e a sincronización de ficheiros na nube atinxen os principais obstáculos: bibliotecas comoexpo-filesystem
soporta a selección básica de ficheiros, pero a travesía recursiva sobre os directorios de iCloud profundamente anexadosoften failed or even caused app crashesIsto fixo evidente que aJavaScript-based approach introduced more complexitymáis que só traballar coas APIs nativas de Apple, aínda que significase unha curva de aprendizaxe máis íngreme.
O sandboxing de iOS impide que as aplicacións lean ficheiros sen permiso explícito do usuario, o que significou que React Native non podía acceder a carpetas externas de forma fiable.
Cambio para SwiftUI
Fun conSwiftUIen lugar de UIKit ou storyboards porque eu quería unhaclean and declarative UIunha capa que quedaría fóra do camiño mentres me enfocaba na lóxica do dominio e a sincronización de datos.Con características modernas como async/await e integración conSwift ActorsSwiftUI tamén fixo máis fácil estruturar a aplicación en compoñentes ViewModel illados, o que á súa vez me axudou a obter mellores resultados de LLMs como OpenAI o1 e DeepSeek.
Arquitectura de aplicacións e modelo de datos
Pasemos á arquitectura da aplicación que creei: usei SQLite para almacenamento de datos persistente e acheguei a arquitectura da aplicación como unha aplicación de servidor simple. Evitei CoreData porque necesitaba un control apertado sobre o esquema, as consultas en bruto e especialmente a busca de texto completo.
Tres pantallas principais
The app consists of 3 screen/modes:
- Importación da biblioteca. Aquí é onde engades a túa carpeta da biblioteca de iCloud. A aplicación escanea cada carpeta para ficheiros de audio e inserta cada camiño nunha base de datos SQLite. Desta forma, podes ter toda a flexibilidade na busca, engadindo carpetas e subcarpetas. O selector de ficheiros nativo de Apple é moi clunky; non podes seleccionar múltiples directorios que buscas por palabra clave e logo tamén un montón de ficheiros nunha soa volta.
- Xestión da biblioteca. Aquí é onde podes xestionar as cancións engadidas e organizar listas de reprodución. Para a maior parte, reflectín a forma en que Apple fixo iso na súa aplicación de música, e foi o suficientemente bo para as miñas necesidades.
- Esta parte da aplicación xestiona a xestión da cola (repeat, shuffle), etc., e a funcionalidade de reprodución, parada e seguinte canción.
Un simple diagrama de fluxo de usuario é mostrado aquí:
User flow in practice:Cando a aplicación se lanza cunha biblioteca baleira, aterra na pestana de sincronización, mostrando un gran botón "Adicionar fonte de iCloud". Escolla unha carpeta alí, e a pantalla de sincronización amosa unha barra de progreso mentres camiña pola árbore.Playlists / Artists / Albums / SongsMergulle en calquera lista, toque nunha pista, e un Mini-Player aparece ao longo do fondo; toque na minibar para abrir o reproductor de pantalla completa con shuffle, repetir, reordenar a cola e volume. Swipe ou toque no ícono de peche, e estás de volta á Biblioteca mentres continúa a reprodución. En calquera momento que necesites máis música, volva a Sincronizar, pulse o "+" na barra de nav, seleccione outra carpeta e o servizo de importación fusionará novas cancións no fondo, sen necesidade de reiniciar.
Backend-Like Lóxica Layer
Tendo un fondo web / nube e enviando unha morea de código de servidor mentres traballaba en startups, fun cunbackend-like architecturePara a aplicación móbil, todo o dominio / capa lóxica foi separado daView and View-Model layerporque tiven que poñer acloud syncing, metadata parsingaspecto da aplicación e ter acceso a datos limpos a un SQLite DB.Aquí está un diagrama aproximado de arquitectura de capas que usei aquí:
How the layers talk:SQLite sitúase na parte inferior, almacenando liñas de cancións crúas e índices FTS. Entón os repositorios envolven a base de datos e expoñen as API asínc.domain actors, Actores Swift que posúen todas as regras de negocio (importación, busca, lóxica de cola) para que as mutacións de estado permanezanthread-safeViewModels subscriben aos actores, transforman os datos en estruturas preparadas para a interfaz de usuario, e as vistas de SwiftUI simplemente renderizan o que reciben.nicely decoupled.
Implementación de Busca de texto completo con SQLite
Como mencionei anteriormente, é afortunado que poida importar unha versión SQLite con capacidades FTS: comezando en torno a iOS 11, está dispoñible fóra da caixa.without extra setupIsto facilitou a integración da busca fuzzy na miña biblioteca de música.without any third-party dependenciesAdemais, usei a biblioteca SQLite.swift para consultas regulares (que funciona como unha especie de construtor de consultas con seguridade de compilación); con todo, para consultas FTS, tiven que recorrer a declaracións SQL regulares.
EscoitadeXestión FTS5A extensión acabou sendo unha das pezas máis valiosas da arquitectura. Permitiume consultar nomes de ficheiros e metadatos como artista, álbum e título sen infraestrutura de indexación adicional.
Creación das táboas FTS
Domain |
Swift actor / repo |
FTS5 table |
Columns that get indexed |
---|---|---|---|
Library songs |
|
|
|
Source-browser paths |
|
|
|
Cancións da Biblioteca
SQLiteSongRepository
songs_fts
artist
,title
,album
,albumArtist
Páxinas de navegación
SQLiteSourcePathSearchRepository
source_paths_fts
fullPath
,fileName
As seguintes páxinas ligan con Categoría:Álbums, Categoría:Álbums, Categoría:Álbums, Categoría:Álbums, Categoría:Álbums, Categoría:Álbumssongs
,source_paths
O FTS éread-only for the UITodos os escritos ocorren dentro dos repositorios para que nada escorrese polas fendas.
Creación do índice de busca
O built-in FTS5 de SQLite fai que as buscas rápidas sexan fáciles.
try db.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
songId UNINDEXED,
artist, title, album, albumArtist,
tokenize='unicode61'
);
""")
que useiunicode61
tokenizer para asegurar que se trate dunha ampla variedade de caracteres.UNINDEXED
Por iso non quita o dicionario da palabra.
Actualización de datos de forma fiable
Para manter as cousas sinxelas e seguras, enviei actualizacións e insercións en transaccións. Isto asegura que o índice de busca nunca saia de sincronización, mesmo se a aplicación se detén ou se interrompe.
func upsertSong(_ song: Song) async throws {
db.transaction {
// insert or update main song data
// insert or update search index data
}
}
Buscar con Fuzzy Busca
Para unha busca fácil de usar, engado o soporte de wildcard automaticamente. Se escribe "lumine", busca "lumine*" internamente, dando resultados instantáneos mesmo con consultas parciais.
Tamén aproveito o ranking intelixente integrado de SQLite (bm25
) para devolver resultados máis relevantes sen complexidade adicional:
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 ?;
En xeral, o uso de SQLite bruto deume a flexibilidade que necesitaba: esquema previsible, acceso local primeiro e poderosa busca de texto completo, sen introducir dependencias de rede ou servizos externos.
Traballar con ficheiros e marcadores
En iOS, as aplicacións poden almacenar marcadores persistentes para localizar ficheiros, perosecurity-scoped bookmarks, que permiten o acceso estendido a ficheiros fóra da caixa de area da aplicación, só están dispoñibles enmacOSAs aplicacións de iOS poden usar marcadores regulares para lembrar os camiños de ficheiros e solicitar o acceso de novo a través do selector de documentos, pero ese acceso non está garantido para persistir silenciosamente.Documentación de Bookmark de Apple.
Para mitigar isto, implantei un mecanismo de retroceso que copia os ficheiros naapp's own sandboxed containerIsto evita o ciclo de vida fráxil de marcadores de seguridade que poden romper silenciosamente se iOS reseta os permisos. Ao copiar ficheiros de forma proactiva no fondo, mentres o marcador sexa válido, non hai risco de acceder a referencias de ficheiros de audio inválidas.
Este enfoque tamén mellora a velocidade de indexación.Podo escanear a estrutura da carpeta unha vez (mentres o acceso estea activo), importar só ficheiros de audio relevantes e cruzar con seguridade directorios profundamente anexados.Pero reproducir de forma fiable ficheiros de audio individuais desde localizacións externas, especialmente despois de reiniciar o dispositivo.Queda un problema non resolto para minIsto destaca comounder-supportedeste caso de uso é, mesmo para aplicacións nativas, e o complexo que aínda é parahandle file access reliably on iOS.
Creación do Playback e UI
Metadatos Parsing
Para analizar os metadatos dos arquivos de audio, usei os de Apple.AVFoundation frameworkEn concreto, oAVURLAssetclase, que permite a inspección de metadatos de ficheiros de medios, como título, artista de álbums, etc. Mentres a análise de metadatos é manexada polo SDK nativo, certos campos como números de rastrexo que ten que buscar manualmente desde as etiquetas ID3.Busca en GitHubpara atopar exemplos, xa que a documentación oficial carecía de cobertura para casos de borda.
Reprodución de audio con AVFoundation
Despois de que a biblioteca estea indexada, implementar un reproductor de audio é bastante sinxelo: só tes que inicializar unha instancia deAVAudioPlayer
Ademais, para as características de calidade de vida: xogar música desde o centro de control, tiven que implementar oAVAudioPlayerDelegate
O protocolo e tamén atópanse en AppleMPRemoteCommandCenter
, que permite aos desenvolvedores responder aos controis de reprodución a nivel do sistema.
Reflexións: Apple, Lock-In para desenvolvedores e o futuro
Aquí está o que se destacou durante o desenvolvemento:
Os malos
Xcode's limitations remain frustrating.As previsións de SwiftUI en tempo real son definitivamente un paso adiante, pero a experiencia xeral de desenvolvemento aínda non está en par con o que Flutter ofreceu hai cinco anos: integración de VSCode estreita, recargas de simuladores en tempo real e ferramentas de depuración coñecidas.
Lack of editor flexibility.Configurar o soporte de Protocolo de servidor de linguaxe (LSP) para Swift en Neovim ou VSCode require ferramentas adicionais comoxcode-build-server
, e aínda non coincide plenamente coa experiencia do desenvolvedor dos ecosistemas web-first.
Some corners of Apple's SDK still live in Objective-C land.A busca de ficheiros Spotlight, por exemplo, só se expón a través deNSMetadataQuery
, que usa Key-Value Observing (KVO) e chaves de cadea, aínda non hai envoltorio amigable con Swift.
SwiftUI's declarative UI is great, but debugging iCloud interactions still requires manual mocks.As previsións de SwiftUI non poden emular os comportamentos de aplicacións completos que involucran os dereitos de iCloud, polo que ten que burlarse das interaccións na nube manualmente, unha molestia menor pero notable.
O bo
Async/await.Por último, podo escribir I / O-bound código simultáneo como un imperativo sen chamadas de volta molesta. que é unha gran vitoria, e aprecio moito o fácil que é escribir mesmo código de sincronización en Actors e chamalo como fai en ecosistemas JavaScript.
Plethora of native libs.Si, non está limitado por vínculos de código aberto como no ecosistema React Native/Flutter. Aquí ten moito máis liberdade para desenvolver algo "máis serio" que a substitución do sitio web da súa empresa / produto (debido á mala experiencia móbil-primeiro).
SwiftUISi, o enfoque de estilo React para a construción de UI dá máis produtividade e espazo para exploracións.
Resumo: A construción debería ser máis sinxela
Despois de 1,5 semanas de hacking ao redor, puiden obter a peza de software que satisfai exactamente as miñas necesidades:local/offline music playerque pode importar arquivos de audio do almacenamento en nube.
Pero os desenvolvedores rapidamente se dan conta de que non poden facilmente implantar aplicacións nos seus propios dispositivos estes días e esquecer sobre iso: as aplicacións só se executan para7 días sen un certificado de dev, e despois diso, ten que reconstruílo, a menos que pagase $ 99 a Apple para inscribirse no programa de desenvolvemento.
7 días sen un certificado de devAínda que despois doDMA Act in the EUOs usuarios da UE agora poden instalar aplicacións de mercados de terceiros directamente desde o sitio dun desenvolvedor, pero só se ese desenvolvedor aínda se inscribiu no programa de $ 99 / ano de Apple e acepta os Termos Alternativos de Apple.
Unha empresa de tecnoloxía innovadora pon activamente barreiras ao desenvolvemento de aplicacións democratizadas.fronte a limitacións notables en iOS: mesmo despois das actualizacións de 16-18.x de Apple, os PWA de iOS aínda se executan dentro da caixa de area de Safari. Obteñen WebGL2 e web-push, pero non obteñen Web Bluetooth / USB / NFC, Background Sync, ou máis de ~50MB de almacenamento garantido. WebGL corre a través de Metal shim, polo que as taxas de cadro do mundo real moitas veces rastrexan aplicacións nativas de Metal; isto é o suficientemente bo para UI, pero non para xogos 3D AAA.
Hoxe en día, a IA reduciu a complexidade do desenvolvemento de software moderno ao permitir a calquera abordar tecnoloxías descoñecidas proporcionando todo o coñecemento necesario dun xeito accesible. Pode ver claramente como o desenvolvemento web adquiriu máis interese de persoas non técnicas que teñen unha forma de construír as súas ideas sen especializarse nunha abundancia de tecnoloxías.Mesmo se o construíches ti mesmo, para ti mesmo, Apple aínda ten a última palabraantes de que poida executalo por máis dunha semana.A mesma empresa que outorgou poder aos desenvolvedores independentes agora impóntight restrictions that hinder personal app developmentA IA facilitou máis que nunca a construción de novas ferramentas, a menos que esteas construíndo para iOS, onde a porta aínda está pechada.
Ligazóns relacionadas
- iTunes Match - Soporte de Apple
- Páxinas na categoría "Apple Docs"
- FTS5 - Documentación SQLite
- Xogador de música Doppler - App Store
- Documentación do sistema de ficheiros de Expo
- Información do programa de desenvolvedores de Apple (7 edicións de día)
- Comunidade de Apple: Aplicación de arquivos e reprodución de MP3