En 2025, jugar la teva pròpia música en un iPhone és sorprenentment difícil, llevat que paguis a Apple o naveguis per un laberint de limitacions.
El 2025, jugant el seu propimusic on an iPhone is surprisingly hard, llevat que pagueu Apple o navegueu per un laberint de limitacions.full text search,iCloud support, i alocal-first experience. elEnllaç GitHub
Per què he construït el meu propi reproductor d'àudio
Com moltes persones, he recollit massa subscripcions, algunes a través d'Apple (iCloud, Apple Music), altres es van perdre en plataformes aleatòries (com Netflix, que vaig oblidar que encara estava pagant).
Inicialment vaig pensar que només continuaria utilitzant la Biblioteca de Música d'iCloud per a la sincronització de música entre dispositius, però una vegada que vaig cancel·lar la subscripció a Apple Music, la sincronització va deixar de funcionar.behind a paywallTècnicament es pot recuperar a través deJocs d'iTunes($ 24,99 per any). Match només emmagatzema 256-kbps còpies AAC en línia; els seus arxius originals es queden posats llevat que vostè decideixi reemplaçar-los. En un Mac modern, vostè fa tot això a l'aplicació de música.
Jocs d'iTunesfrustrat per la falta d’opcions, vaig anar albuilder routeSi vaig comprar un dispositiu informàtic (iPhone en aquest cas), què em impedeix de construir exactament el que necessito amb codi per utilitzar-lo? En aquest article, vull compartir el meu viatge complet de frustracions cap a la creació d'una funcionalitat de reproducció de música bàsica: carregar arxius d'àudio, organitzar-los i reproduir-los, però sobretot, vaig voler recordar-me,encara és un ordinador de propòsit general, hauria de ser capaç de fer el que vulgui.
Què ofereix Apple (i altres) avui
Abans d'escriure la meva pròpia aplicació, vaig explorar les opcions oficials i de tercers per a la reproducció de música fora de línia.
Aplicacions incorporades d'Apple
Apple tècnicament li permet reproduir música directament des de iCloud a través de l'aplicació Arxius, però la seva funcionalitat no està dissenyada per a l'escolta de música.lacks essential featurescom ara la gestió de les llistes de reproducció, la classificació de metadades o les files de reproducció. Tot i que dóna suport a la reproducció de música, és molt limitada i global.not a good user experience.
No una bona experiència d'usuariAplicacions de tercers
Vaig anar a la botiga d'aplicacions a la recerca d'aplicacions cool que resolguin el meu problema, mentre que n'hi ha molts, molts de confiar ensubscription-based pricing, un model qüestionable per a una aplicació que simplement reprodueix arxius que els usuaris ja posseeixen.DopplerHe jugat amb ella durant un assaig, però la UX està construïda al voltant de la gestió d'àlbums. La cerca no va ser tan bona, i la funcionalitat d'importació d'iCloud va ser lenta i difícil d'utilitzar en un gran nombre de carpetes embolicades.
Going Builder Mode: El meu viatge tècnic
Amb això dit, vaig decidir crear el meu propi reproductor de música ideal que resol els meus punts de dolor:
- Busca flexible de text complet a través de les carpetes d'iCloud, de manera que puc seleccionar i importar ràpidament una carpeta amb música o arxius específics.
- Funcionalitat en la gestió de la música almenys en paritat amb l'aplicació oficial de la música: cua, gestió de llistes de reproducció i classificació per àlbums, etc.
- Interfície familiar i amigable.
Intentant reaccionar natiu primer
Fa uns anys, em va agradar la sintaxi (sentí més a prop de TypeScript) i va apreciar la seguretat de la memòria com Rust, però sense nadius.async
/await
En aquell moment, escriure codi simultani en comparació amb Go o JS / TS va semblar cluny i boilerplate pesat.Aquesta experiència em va deixar frustrat, així que quan vaig revisitar aquest projecte, inicialment vaig arribar a alguna cosa més familiar.
Dit això, vaig anar amb React Native o Expo, amb l'esperança de reutilitzar la meva experiència de desenvolupament web i connectar una interfície d'usuari del jugador a partir de plantilles existents. la construcció de la interfície d'usuari de reproducció va ser senzilla; hi ha nombrosos exemples de codi obert i vídeos tutorial sobre la construcció de jugadors de música de bon aspecte que s'ajustin a les meves necessitats.Projecte de temples de Gionatha Sturba, perquè semblava tenir totes les característiques que necessito per a la meva aplicació.
L'accés al sistema de fitxers i la sincronització d'arxius en el núvol colpeixen grans obstacles: biblioteques comexpo-filesystem
Suporta la selecció bàsica de fitxers, però la travessia recursiva a través de directoris iCloud profundament incrustatsoften failed or even caused app crashesAixò ha deixat clar que aJavaScript-based approach introduced more complexityque només treballar amb les APIs natives d'Apple, fins i tot si significava una corba d'aprenentatge més abrupta.
El sandboxing d'iOS impedeix que les aplicacions llegeixin arxius sense el permís explícit de l'usuari, cosa que significa que React Native no podia accedir de manera fiable a carpetes externes.
Canviar a SwiftUI
Vaig anar ambSwiftUIen lloc d'UIKit o storyboards perquè jo volia unclean and declarative UIcapa que quedaria fora de la manera mentre em vaig centrar en la lògica del domini i la sincronització de dades. Amb característiques modernes com async/await i integració ambSwift ActorsSwiftUI també va fer més fàcil estructurar l'aplicació en components ViewModel aïllats, que al seu torn em va ajudar a obtenir millors resultats de LLMs com OpenAI o1 i DeepSeek. LLMs podrien produir codi UI pur o codi de vinculació de dades sense introduir interdependències confuses.
Arquitectura d'aplicacions i model de dades
Anem a l'arquitectura de l'aplicació que he creat: vaig utilitzar SQLite per a l'emmagatzematge de dades persistent i vaig abordar l'arquitectura de l'aplicació com una aplicació de servidor simple. vaig evitar CoreData perquè necessitava un control estret sobre l'esquema, les consultes brutes i especialment la cerca de text complet.
Tres pantalles principals
The app consists of 3 screen/modes:
- Importació de la biblioteca. Aquí és on afegiu la vostra carpeta de la biblioteca d'iCloud. L'aplicació escaneja cada carpeta per a arxius d'àudio i insereix cada camí a una base de dades SQLite. D'aquesta manera, podeu tenir tota la flexibilitat en la cerca, l'addició de carpetes i subcarpetes. El selector de fitxers natiu d'Apple és molt cluny; no podeu seleccionar múltiples directoris que heu buscat per paraula clau i després també un munt de fitxers en un sol pas. Simplement no està dissenyat per fer això.
- Gestió de biblioteques. Aquí és on podeu gestionar les cançons afegides i organitzar les llistes de reproducció. Per la major part, he reflectit la manera com Apple ho va fer en la seva aplicació de música, i va ser prou bo per a les meves necessitats.
- Aquesta part de l'aplicació gestiona la gestió de la cua (repeat, shuffle), etc., i la funcionalitat de reproducció, parada i cançó següent.
Un simple diagrama de flux d'usuari es mostra aquí:
User flow in practice:Quan l'aplicació s'inicia amb una biblioteca buida, aterra a la pestanya de Sincronització, mostrant un botó gran "Adicionar font d'iCloud". Tria una carpeta allà, i la pantalla de Sincronització mostra una barra de progrés mentre camina per l'arbre.Playlists / Artists / Albums / SongsSubmergiu-vos en qualsevol llista, toqueu una pista, i un Mini-Player apareix al llarg de la part inferior; toqueu aquesta mini-bar per obrir el reproductor de pantalla completa amb shuffle, repetir, reordenar la cua i volum. Swipe o toqueu la icona de tancament, i esteu directament de tornada a la Biblioteca mentre continua la reproducció. En qualsevol moment que necessiteu més música, torneu a Sincronitzar, toqueu el "+" a la barra de nav, seleccioneu un altre carpeta, i el servei d'importació fusionarà noves cançons en el fons, no cal reiniciar.
Backend-Like Lloc lògic
Tenint un fons web / núvol i enviant una gran quantitat de codi del servidor mentre treballava en startups, vaig anar amb unbackend-like architectureper a l'aplicació mòbil. Tot el domini / capa lògica es va separar de laView and View-Model layerPerquè vaig haver de fer elcloud syncing, metadata parsingaspectes de l'aplicació i tenir accés a dades netes a un SQLite DB.Aquí teniu un diagrama d'arquitectura de capes que he utilitzat aquí:
How the layers talk:SQLite es troba a la part inferior, emmagatzemant les files de cançons crues i els índexs FTS. Després, els repositoris embolcallen la base de dades i exposen les APIs async.domain actorsActors Swift que posseeixen totes les regles de negoci (importació, cerca, lògica de cua) de manera que les mutacions d'estat es mantinguin.thread-safeViewModels subscriuen als actors, transformen les dades en estructures preparades per a la interfície d'usuari, i les vistes de SwiftUI simplement mostren el que obtenen.nicely decoupled.
Implementació de la cerca de text complet amb SQLite
Com he esmentat anteriorment, és afortunat que es pugui importar una versió SQLite amb capacitats FTS: a partir d'iOS 11, està disponible fora de la caixa.without extra setupAixò ha facilitat la integració de la cerca fuzzy a la meva biblioteca de música.without any third-party dependenciesA més, vaig utilitzar la biblioteca SQLite.swift per a consultes regulars (que funciona com una mena de constructor de consultes amb seguretat de temps de compilació); però, per a consultes FTS, vaig haver de recórrer a declaracions SQL regulars.
Escletxa deEl FTS5L'extensió va acabar sent una de les peces més valuoses de l'arquitectura. Em va permetre consultar noms de fitxers i metadades com a artista, àlbum i títol sense una infraestructura d'indexatge addicional.
Instal·lació de les taules FTS
Domain |
Swift actor / repo |
FTS5 table |
Columns that get indexed |
---|---|---|---|
Library songs |
|
|
|
Source-browser paths |
|
|
|
Cançons de biblioteca
SQLiteSongRepository
songs_fts
artist
,title
,album
,albumArtist
Rutes del navegador
SQLiteSourcePathSearchRepository
source_paths_fts
fullPath
,fileName
He utilitzat dues taules FTS5: una per a cançons indexades (artista/títol/àlbum) i una per a camins d'arxiu durant la importació de carpetes.songs
,source_paths
El FTS ésread-only for the UITots els escrits es produeixen dins dels repositoris, de manera que res no s'escampa a través de les esquerdes.
Creació de l'índex de cerca
El built-in FTS5 de SQLite fa que les cerques ràpides siguin fàcils.Aquí hi ha una definició de taula simple que he utilitzat:
try db.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
songId UNINDEXED,
artist, title, album, albumArtist,
tokenize='unicode61'
);
""")
Utilitzemunicode61
tokenizer per assegurar que es tracti d'una àmplia varietat de caràcters.UNINDEXED
Per tant, no s’ha d’esborrar el diccionari.
Actualitzar les dades de manera fiable
Per mantenir les coses senzilles i segures, he embolicat actualitzacions i insercions en transaccions. Això assegura que l'índex de cerca mai no surti de sincronització, fins i tot si l'aplicació es trenca o es fa interrompuda.
func upsertSong(_ song: Song) async throws {
db.transaction {
// insert or update main song data
// insert or update search index data
}
}
Buscar amb Fuzzy Search
Per a una cerca fàcil d'utilitzar, afegeixo el suport de wildcard automàticament. Si escrius "lumine", cercarà "lumine*" internament, donant resultats immediats fins i tot amb consultes parcials.
També utilitzo el rànquing intel·ligent integrat de SQLite (bm25
) per retornar resultats més rellevants sense complexitat addicional:
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 general, l'ús de SQLite cru em va donar la flexibilitat que necessitava: esquema predictible, accés local primer i poderosa cerca de text sencer, sense introduir cap dependència de xarxa o serveis externs.
Treballar amb els arxius i els marcadors
A iOS, les aplicacions poden emmagatzemar marcadors persistents per localitzar arxius, peròsecurity-scoped bookmarks, que permeten l'accés estès als arxius fora de la sandbox de l'aplicació, només estan disponibles enmacOSLes aplicacions d'iOS poden utilitzar marcadors regulars per recordar camins d'arxiu i sol·licitar l'accés de nou a través del selector de documents, però aquest accés no està garantit per persistir en silenci.Documentació de bookmark d'Apple.
Per mitigar això, vaig implementar un mecanisme de fallback que copia els arxius a laapp's own sandboxed containerAixò evita el cicle de vida fràgil dels marcadors de seguretat que poden trencar silenciosament si iOS restableix els permisos.Amb la còpia de fitxers de forma proactiva en el fons, mentre que el marcador és vàlid, no hi ha risc d'accedir a referències de fitxers d'àudio no vàlides.
Aquest enfocament també millora la velocitat d'indexació. Puc escanejar l'estructura de la carpeta una vegada (mentre l'accés és actiu), importar només arxius d'àudio rellevants i creuar de forma segura directoris profundament incrustats.Un problema sense solució per a miAixò posa de relleu comunder-supportedaquest cas d'ús és, fins i tot per a les aplicacions natives, i com de complex encara éshandle file access reliably on iOS.
Creació de Playback i UI
Metadades Parsing
Per analitzar les metadades dels arxius d'àudio, vaig utilitzar la tecnologia d'Apple.AVFoundation frameworkEn concret, elAVURLAssetclasse, que permet la inspecció de metadades de fitxers de mitjans, com el títol, l'artista d'àlbums, etc. Mentre que l'anàlisi de metadades es gestiona per l'SDK natiu, certs camps com els números de seguiment s'han de buscar manualment a partir de les etiquetes ID3.Cerca de GitHubper trobar exemples, ja que la documentació oficial no tenia cobertura per a casos d'avantguarda.
Reproducció d'àudio amb AVFoundation
Després de la indexació de la biblioteca, la implementació d'un reproductor d'àudio és bastant simple: només has d'iniciar una instància d'àudio.AVAudioPlayer
A més, per a les característiques de qualitat de vida: reproduir música des del centre de control, vaig haver d'implementar laAVAudioPlayerDelegate
El protocol i també lligat a l'AppleMPRemoteCommandCenter
, que permet als desenvolupadors respondre als controls de reproducció a nivell del sistema.
Reflexions: Apple, Lock-In per a desenvolupadors i el futur
Aquí teniu el que es va destacar durant el desenvolupament:
El mal
Xcode's limitations remain frustrating.Les visualitzacions en temps real de SwiftUI són sens dubte un pas endavant, però l'experiència general de desenvolupament encara no està a l'alçada del que Flutter va oferir fa cinc anys: estreta integració de VSCode, carregaments de simuladors en temps real i eines de debugging familiars.
Lack of editor flexibility.La configuració del suport de Language Server Protocol (LSP) per a Swift en Neovim o VSCode requereix eines addicionals com araxcode-build-server
, i encara no coincideix plenament amb l'experiència del desenvolupador dels ecosistemes web-first.
Some corners of Apple's SDK still live in Objective-C land.La cerca de fitxers Spotlight, per exemple, només s'exposa a través deNSMetadataQuery
, que utilitza l'observació de valors clau (KVO) i les claus de cadena, encara no hi ha cap embolcall amigable amb Swift.
SwiftUI's declarative UI is great, but debugging iCloud interactions still requires manual mocks.Les previstes de SwiftUI no poden emular el comportament complet de les aplicacions que involucren els drets d'iCloud, de manera que heu de burlar-vos de les interaccions en el núvol manualment, una molèstia menor però notable.
El bon
Async/await.Finalment, puc escriure codi simultani I/O-bound com un imperatiu sense trucades molestes.És una gran victòria, i aprecio molt com és fàcil escriure fins i tot el codi de sincronització en Actors i cridar-lo com ho fa en els ecosistemes de JavaScript.
Plethora of native libs.Sí, no estàs limitat per vinculacions de codi obert com en els ecosistemes React Native/Flutter. Aquí tens molt més llibertat per desenvolupar alguna cosa "més seriosa" que el reemplaçament del lloc web de la teva empresa / producte (a causa de la mala experiència de primer mòbil).
SwiftUISí, l'enfocament d'estil React per a la construcció d'interfícies d'usuari dóna més productivitat i espai per a les exploracions.
Títol: La construcció hauria de ser més fàcil
Després de 1,5 setmanes d'hacking al voltant, vaig poder obtenir la peça de programari que satisfà exactament les meves necessitats: unalocal/offline music playerque pot importar arxius d'àudio des de l'emmagatzematge en núvol.
Però els desenvolupadors ràpidament s'adonen que no poden desplegar fàcilment aplicacions als seus propis dispositius aquests dies i oblidar-ho: les aplicacions només s'executen per a7 dies sense un certificat de Dev, i després d'això, has de reconstruir-lo, tret que hagis pagat 99 dòlars a Apple per inscriure't al programa de desenvolupament.
7 dies sense un certificat de DevFins i tot després de laDMA Act in the EUEls usuaris de la UE ara poden instal·lar aplicacions de mercats de tercers directament des del lloc d'un desenvolupador, però només si aquest desenvolupador segueix inscrit en el programa de $ 99 / any d'Apple i accepta les condicions alternatives d'Apple.
Això no té cap sentit en última instància.Una empresa tecnològica innovadora col·loca activament barreres en el desenvolupament d'aplicacions democratitzades.Limitacions significatives en els: fins i tot després de les actualitzacions 16-18.x d'Apple, els PWA d'iOS encara s'executen dins de la caixa de sorra de Safari. obtenen WebGL2 i web-push, però no obtenen Web Bluetooth / USB / NFC, sincronització de fons, o més de ~50MB d'emmagatzematge garantit. WebGL s'executa a través de Metal shim, de manera que les taxes de marc del món real sovint segueixen les aplicacions natives de Metal; això és prou bo per a la interfície d'usuari, però no per als jocs 3D AAA.
Avui en dia, la IA ha reduït la complexitat del desenvolupament de programari modern permetent a qualsevol abordar tecnologies desconegudes proporcionant tot el coneixement necessari d'una manera accessible.Podeu veure clarament com el desenvolupament web ha tingut més interès de les persones no tècniques que tenen una manera de construir les seves idees sense especialitzar-se en una multitud de tecnologies.Fins i tot si ho heu construït vosaltres mateixos, per vosaltres mateixos, Apple encara té l'última paraulaabans que puguis executar-lo durant més d'una setmana.La mateixa empresa que un cop va empoderar els desenvolupadors independents ara imposatight restrictions that hinder personal app developmentIA ha fet que sigui més fàcil que mai construir noves eines, tret que estiguis construint per a iOS, on la porta encara està tancada.
Esquerres relacionades
- iTunes Match - Suport d'Apple
- Etiquetes de comentaris - Apple Docs
- FTS5 - Documentació SQLite
- El reproductor de música Doppler - App Store
- Documentació de l'Expo FileSystem
- Informació del programa de desenvolupadors d'Apple (7 edicions de dia)
- Comunitat d'Apple: Aplicació d'arxius i reproducció de MP3