U 2025, sviranje vlastite muzike na iPhone-u je iznenađujuće teško, osim ako ne platite Apple ili se krećete kroz labirint ograničenja.
U 2025, sviranje vlastite muzike na iPhone-u je iznenađujuće teško, osim ako ne platite Apple ili se krećete kroz labirint ograničenja.
Zašto sam izgradio svoj vlastiti audio player
Kao i mnogi ljudi, prikupio sam previše pretplata, neki kroz Apple (iCloud, Apple Music), drugi su izgubljeni na slučajnim platformama (kao što je Netflix, za koji sam zaboravio da još uvijek plaćam).
U početku sam mislio, samo bih nastavio koristiti iCloud Music Library za sinhronizaciju muzike između uređaja, ali nakon što sam otkazao pretplatu na Apple Music, sinhronizacija je prestala raditi.behind a paywallTehnički ga možete vratiti putemiTunes utakmica($ 24.99 za godinu dana). Match samo skladišti 256-kbps AAC kopije online; vaše izvorne datoteke ostaju stavljene, osim ako ih ne odlučite zamijeniti. Na modernom Macu, sve to radite u aplikaciji Music. Bez bilo koje pretplate, sinhronizacija u oblaku je nestala, a vi ste se vratili na sinhronizaciju kablova/Wi-Fi.
iTunes utakmicaFrustriran nedostatkom opcija, otišao sam nabuilder routeAko sam kupio računarski uređaj (iPhone u ovom slučaju), šta me sprečava da izgradim upravo ono što mi je potrebno kodom za njegovu upotrebu?U ovom članku, želim podijeliti svoj ceo put frustracija prema stvaranju osnovne funkcionalnosti glazbene reprodukcije: učitavanje audio datoteka, organizovanje i reprodukcija, ali uglavnom, hteo sam da se podsjetim,ovo je još uvek opšte namjene računalo, ja bih trebao biti u mogućnosti da ga učiniti ono što želim.
Šta Apple (i drugi) nude danas
Prije nego što sam napisao vlastitu aplikaciju, istražio sam službene i treće strane opcije za offline reprodukciju glazbe.
Ugrađene aplikacije Apple
Apple vam tehnički omogućuje da reprodukujete muziku direktno iz iClouda putem aplikacije Datoteke, ali njegova funkcionalnost nije dizajnirana za slušanje muzike.lacks essential featureskao što su upravljanje listama za reprodukciju, sortiranje metapodataka ili redovi za reprodukciju. Dok podržava reprodukciju muzike, vrlo je ograničena i ukupnaNije dobro korisničko iskustvo.
Nije dobro korisničko iskustvoAplikacije treće strane
Otišao sam u prodavnicu aplikacija da potražim cool aplikacije koje rješavaju moj problem, dok ih ima mnogo, mnogi se oslanjaju nasubscription-based pricing, sumnjiv model za aplikaciju koja jednostavno igra datoteke koje korisnici već poseduju.DoppleroviIgrao sam s njim tokom pokusa, ali UX je izgrađen oko upravljanja albumima. pretraživanje nije bilo tako dobro, a funkcionalnost uvoza iz iClouda bila je spora i teška za upotrebu na velikom broju ugrađenih fascikli.
Going Builder Mode: Moje tehničko putovanje
S tim rečeno, odlučio sam stvoriti svoj idealan glazbeni plejer koji rješava moje bolne točke:
- Fleksibilno pretraživanje punog teksta kroz iCloud fascikle, tako da mogu brzo odabrati i uvoziti fasciklu sa muzikom ili određenim datotekama.
- Funkcionalnost u upravljanju muzikom barem na istom nivou kao i zvanična aplikacija za muziku: red, upravljanje playlistom i sortiranje po albumima, itd.
- Poznati i prijateljski interfejs.
Pokušajte prvo reagovati native
Prije nekoliko godina, volio sam sintaksu (osjećao se bliže TypeScript-u) i cenio sigurnost memorije poput Rust-a, ali bez nativeasync
/await
u to vrijeme, pisanje istovremenog koda u usporedbi s Go ili JS / TS osjećao klunky i boilerplate-teška.To iskustvo me ostavio frustriran, tako da kada sam ponovo posetio ovaj projekt, ja sam u početku došao za nešto više upoznat.
To je rekao, otišao sam sa React Native ili Expo, nadajući se da ću ponovno iskoristiti svoje iskustvo web razvoja i priključiti korisnički interfejs igrača iz postojećih predloška. Izgradnja korisničkog interfejsa za reprodukciju bila je jednostavna; postoje brojni primjeri otvorenog koda i video tutoriali o izgradnji dobrih glazbeni igrači koji odgovaraju mojim potrebama.Projekat template od strane Gionatha Sturba, jer je izgledalo da ima sve funkcije koje su mi potrebne za moju aplikaciju.
Pristupanje datotečnom sistemu i sinhronizacija datoteka u oblaku pogodili su velike prepreke: biblioteke poputexpo-filesystem
Podržan osnovni odabir datoteka, ali recursivno prolazak preko duboko ugrađenih iCloud direktorijumaoften failed or even caused app crashesTo je jasno pokazalo da aJavaScript-based approach introduced more complexitynego samo raditi s Appleovim nativnim API-jima, čak i ako je to značilo oštriju krivulju učenja.
iOS sandboxing sprečava aplikacije da čitaju datoteke bez eksplicitne dozvole korisnika, što znači da React Native ne može pouzdano pristupiti spoljnim fasciklima.
Prebacivanje na SwiftUI
Otišao sam saSwiftUIumjesto UIKit ili storyboards jer sam želeoclean and declarative UIsloj koji bi ostao izvan puta dok sam se usredotočio na logiku domena i sinhronizaciju podataka. S modernim funkcijama kao što su async/await i integracija saSwift ActorsSwiftUI je također definitivno olakšao strukturiranje aplikacije u izolirane ViewModel komponente, što mi je, pak, pomoglo da dobijem bolje rezultate od LLM-ova kao što su OpenAI o1 i DeepSeek.
Aplikacijska arhitektura i model podataka
Hajde da pređemo na arhitekturu aplikacije koju sam stvorio: Koristio sam SQLite za uporno skladištenje podataka i pristupio arhitekturi aplikacije kao jednostavnoj aplikaciji za server. Izbjegao sam CoreData jer mi je potrebna čvrsta kontrola nad shemom, sirovim upitima i posebno potražnjom punog teksta. SQLite-ova ugrađena podrška za FTS5 omogućila mi je da dodam brzo nejasno pretraživanje bez povlačenja teških spoljnih pretraživača ili izgradnje vlastitog sloja indeksiranja.
Tri glavna ekrana
The app consists of 3 screen/modes:
- Uvoz biblioteke. Ovo je mesto gde dodajete svoju iCloud biblioteku fasciklu. Aplikacija skenira svaku fasciklu za audio datoteke i umetne svaki put u SQLite bazu podataka. Na ovaj način, možete imati punu fleksibilnost u pretraživanju, dodavanju fascikli i podfoldera. Appleov prirodni izbornik datoteka je vrlo klonljiv; ne možete odabrati više direktorija koje ste pretražili po ključnoj riječi, a zatim i gomilu datoteka u jednom krugu.
- Upravljanje bibliotekom. Ovde možete upravljati dodanim pjesmama i organizovati liste reprodukcije. U većini slučajeva, ja sam odražavala način na koji je Apple to učinio u svojoj aplikaciji za muziku, i to je bilo dovoljno dobro za moje potrebe.
- Ovaj deo aplikacije upravlja upravljanjem čekom (ponavljanje, shuffle), itd., i funkcijama za reprodukciju, zaustavljanje i sledeću pesmu.
Jednostavan korisnički tok dijagram prikazan je ovde:
User flow in practice:Kada se aplikacija pokrene s praznom bibliotekom, ona sleti na karticu Sync, pokazujući veliki "Dodaj izvor iCloud" dugme. Odaberite fasciklu tamo, a ekran Sync prikazuje traku napretka dok hoda stablom. Čim se indeksiranje završi, prebacuje vas na karticu Knjižnica, čiji prvi zaslon listePlaylists / Artists / Albums / SongsUđite u bilo koju listu, dodirnite stazu, a Mini-Player će se pojaviti uz dno; dodirnite minibar da biste otvorili punom zaslonu Player sa shuffle, ponavljanje, redoslijed reda i volumena. Dodirnite ili dodirnite ikonu za zatvaranje, a vi ste pravo natrag u Knjižnicu dok se reprodukcija nastavlja. Svaki put kada vam treba više muzike, preskočite nazad na Sync, dodirnite "+" u nav traci, izaberite drugu fasciklu, a usluga uvoza spaja nove pesme u pozadini, bez ponovnog pokretanja.
Backend-Like logički sloj
Imajući web / cloud pozadinu i isporučivši puno server koda dok radim u startup-u, otišao sam sabackend-like architectureza mobilnu aplikaciju. Cijeli domen/logički sloj je odvojen odView and View-Model layerjer sam morao da nagnemcloud syncing, metadata parsingaspekt aplikacije i imati čisti pristup podacima na SQLite DB.Evo približnog složenog arhitektonskog dijagrama koji sam koristio ovdje:
How the layers talk:SQLite sjedi na dnu, čuvajući sirove redove pesama i FTS indekse. Zatim repozitorije omotaju bazu podataka i izlažu async API-je.domain actors, Swift akteri koji poseduju sva poslovna pravila (uvoz, pretraživanje, logika reda) tako da državne mutacije ostanuthread-safeViewModels se pretplate na glumce, pretvaraju podatke u strukture spremne za UI, a pogledi SwiftUI jednostavno prikazuju sve što dobiju.nicely decoupled.
Implementacija potrage za punim tekstom pomoću SQLite
Kao što sam ranije spomenuo, sretno je da možete uvoziti verziju SQLite sa mogućnostima FTS: počevši od iOS 11, dostupan je izvan kutijewithout extra setupTo je olakšalo integraciju nejasne pretrage u moju muzičku bibliotekuwithout any third-party dependenciesOsim toga, koristio sam biblioteku SQLite.swift za redovne upite (koji radi kao neka vrsta kreatora upita sa bezbednošću kompilacijskog vremena); međutim, za FTS upite, morao sam se posvetiti redovnim SQL izjavama.
SkladištenjeUslovi FTS5Ekstenzija je na kraju postala jedan od najvrednijih komada arhitekture. To mi je omogućilo da pretražujem imena datoteka i metapodatke poput umjetnika, albuma i naslova bez dodatne infrastrukture za indeksiranje.
Postavljanje FTS tabela
Domain |
Swift actor / repo |
FTS5 table |
Columns that get indexed |
---|---|---|---|
Library songs |
|
|
|
Source-browser paths |
|
|
|
Knjižnica pesme
SQLiteSongRepository
songs_fts
artist
U pitanju jetitle
U pitanju jealbum
U pitanju jealbumArtist
Source-browser putovi
SQLiteSourcePathSearchRepository
source_paths_fts
fullPath
U pitanju jefileName
Koristio sam dve FTS5 tabele: jednu za indeksirane pesme (artist / naslov / album) i jednu za putove datoteka tokom uvoza fascikla.songs
U pitanju jesource_paths
FTS jeread-only for the UISvi pisma se odvijaju unutar repozitorija tako da ništa ne klizi kroz pukotine.
Kreiranje indeksa pretrage
SQLite je ugrađen FTS5 čini brze pretrage lako. Evo jednostavne definicije tabele koje sam koristio:
try db.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
songId UNINDEXED,
artist, title, album, albumArtist,
tokenize='unicode61'
);
""")
Koristio samunicode61
tokenizer kako bi se osiguralo da se rješava širok raspon karaktera. Ne pretraživi ključevi su označeni saUNINDEXED
, tako da ne pucaju termin rječnik.
ažuriranje podataka pouzdano
Da bi stvari bile jednostavne i sigurne, uputila sam ažuriranja i umetnuta u transakcije.To osigurava da indeks pretrage nikada ne izlazi iz sinhronizacije, čak i ako se aplikacija sruši ili prekine.
func upsertSong(_ song: Song) async throws {
db.transaction {
// insert or update main song data
// insert or update search index data
}
}
Uslovi korišćenja za Fuzzy Search
Za korisnički prihvatljive pretrage, automatski dodajem podršku za wildcard. Ako otkucate "lumine", on traži "lumine*" interno, dajući trenutne rezultate čak i sa parcijalnim upitima.
Takođe koristim ugrađenu pametnu rangiranje SQLite-a (bm25
) da vrati relevantnije rezultate bez dodatne složenosti:
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 ?;
Općenito, korišćenje sirovog SQLite-a mi je pružilo fleksibilnost koja mi je bila potrebna: predvidljiva shema, lokalni prvi pristup i moćna potraga punim tekstom, bez uvođenja bilo kakvih mrežnih ovisnosti ili spoljnih usluga.
Rad sa iOS datotekama i beležnicama
Na iOS-u, aplikacije mogu pohraniti trajne beležnice na lokacije datoteke, alisecurity-scoped bookmarks, koji omogućuju proširen pristup datotekama izvan sandbox aplikacije, dostupni su samo namacOS. iOS aplikacije mogu koristiti redovne beležnice da zapamte putove datoteke i zatraže pristup ponovo kroz odabir dokumenata, ali taj pristup nije zajamčen da će trajati tiho.Apple Bookmark dokumentacija.
Da bi se to ublažilo, implementirao sam mehanizam za povratne informacije koji kopira datoteke uapp's own sandboxed containerTime se izbegava krhki životni ciklus beležnica koje su ograničene na sigurnost i koje se mogu tiho slomiti ako iOS resetuje dozvole. Proaktivnim kopiranjem datoteka u pozadinu, dok je beležnica valjana, nema rizika od pristupa nevažećim upućivanjima na audio datoteke.
Ovaj pristup takođe poboljšava brzinu indeksiranja. Mogu skenirati strukturu fascikla jednom (dok je pristup aktivan), uvoziti samo relevantne audio datoteke i sigurno proći kroz duboko ugrađene direktorijume.ostaje neriješen problem za meneTo naglašava kakounder-supportedovaj slučaj upotrebe je, čak i za prirodne aplikacije, i koliko je to još uvek složenohandle file access reliably on iOS.
Izgradnja Playback i UI
Metodologija parsinga
Za analizu metapodataka iz audio datoteka, koristio sam AppleAVFoundation frameworkPosebno naAVURLAssetrazred, koji omogućuje ispitivanje metapodataka medijske datoteke, kao što su naslov, album artist, itd Dok se analiziranje metapodataka rukuje nativnim SDK-om, određena polja kao što su brojevi za praćenje morate ručno potražiti iz ID3 oznaka.GitHub pretraživanjekako bi pronašli primere, budući da službena dokumentacija nije imala pokrivenost za slučajeve na rubu.
Audio reprodukcija sa AVFoundation-om
Nakon što je biblioteka indeksirana, implementiranje audio igrača izgleda prilično jednostavno: samo morate inicijalizirati instanciAVAudioPlayer
Osim toga, za karakteristike kvalitete života: sviranje muzike iz kontrolnog centra, morao sam implementiratiAVAudioPlayerDelegate
Protokola i takođe uhvaćen u AppleMPRemoteCommandCenter
, što omogućuje programerima da odgovore na kontrole reprodukcije na nivou sistema.
Refleksiji: Apple, Developer Lock-In i budućnost
Evo šta je izašlo na vidjelo tijekom razvoja:
loše
Xcode's limitations remain frustrating.SwiftUI predviđanja u realnom vremenu definitivno su korak naprijed, ali opće iskustvo razvoja još uvijek nije na istom nivou s onim što je Flutter ponudio prije pet godina: čvrsta integracija VSCode-a, ponovna učitavanja simulatora u realnom vremenu i poznati alati za debugiranje.
Lack of editor flexibility.Postavljanje podrške za Language Server Protocol (LSP) za Swift u Neovim ili VSCode zahtijeva dodatne alate kao što suxcode-build-server
, i još uvijek ne odgovara u potpunosti iskustvu programera web-first ekosustava.
Some corners of Apple's SDK still live in Objective-C land.Spotlight pretraživanje datoteke, na primjer, je izložena samo krozNSMetadataQuery
, koji koristi Key-Value Observing (KVO) i ključeve niza, još nema Swift-friendly wrapper.
SwiftUI's declarative UI is great, but debugging iCloud interactions still requires manual mocks.SwiftUI pretrage ne mogu emulirati potpuno ponašanje aplikacija koje uključuju iCloud ovlašćenja, tako da morate ručno ismevati interakcije u oblaku, što je manje uznemirujuće, ali značajno.
Dobri
Async/await.Konačno, mogu napisati I/O-bound istovremeno kod kao imperativ bez uznemirujućih povratnih poziva. To je velika pobeda, i jako cijenim koliko je lako napisati čak i sinhronizaciju koda u Actors i nazvati ga kao što to radite u JavaScript ekosustavima.
Plethora of native libs.Da, niste ograničeni vezama otvorenog koda kao u React Native/Flutter ekosustavima. Ovde imate mnogo više slobode u razvoju nečeg "ozbiljnijeg" od zamjene web stranice vaše kompanije/proizvoda (zbog lošeg mobilnog iskustva).
SwiftUIDa, React-style pristup izgradnji korisničkog okvira daje više produktivnosti i prostora za istraživanje.
Sljedeći članak: Izgradnja bi trebala biti lakša
Nakon 1,5 tjedana hakovanja, uspio sam da dobijem komad softvera koji tačno zadovoljava moje potrebe:local/offline music playerkoji može uvoziti audio datoteke iz skladišta u oblaku.
Ali programeri brzo shvate da ne mogu lako distribuirati aplikacije na svoje uređaje ovih dana i zaboraviti na to: aplikacije rade samo za7 dana bez dev certifikata, a nakon toga, morate ga ponovo izgraditi, osim ako niste platili 99 dolara Appleu da se upišete u razvojni program.
7 dana bez dev certifikataČak i nakonDMA Act in the EUKorisnici EU-a sada mogu instalirati aplikacije sa tržišta trećih strana direktno sa web stranice programera, ali samo ako je taj programer još uvek upisan u Appleov program od 99 dolara godišnje i slaže se s Appleovim alternativnim uvjetima.
To u konačnici nema smisla.Inovativna tehnološka kompanija aktivno stavlja prepreke u demokratizovani razvoj aplikacija.suočavanje sa značajnim ograničenjima na iOS: čak i nakon Apple 16-18.x ažuriranja, iOS PWAs i dalje rade unutar Safari sandbox. Oni dobijaju WebGL2 i web-push, ali oni ne dobijaju Web Bluetooth / USB / NFC, Background Sync, ili više od ~50MB zajamčenog skladištenja. WebGL radi kroz Metal shim, tako da realni svet frame rate često prati native Metal aplikacije; to je dovoljno dobro za UI, ali ne i za AAA 3D igre.
Danas, AI je smanjio složenost modernog softverskog razvoja omogućavajući bilo kome da se bavi nepoznatim tehnologijama pružanjem svih potrebnih znanja na pristupačan način. Možete jasno vidjeti kako je web razvoj dobio više interesa od ne-tehničkih ljudi koji imaju način da grade svoje ideje bez specijalizovanja u mnoštvu tehnologija.Čak i ako ste ga izgradili sami, za sebe, Apple još uvijek dobija konačnu rečprije nego što možete da ga pokrenete više od nedelju dana. ista kompanija koja je jednom osnažila nezavisne programere sada namećetight restrictions that hinder personal app developmentUmjetna inteligencija olakšala je nego ikad izgradnju novih alata, osim ako gradite za iOS, gde su vrata još uvek zaključana.
Povezani linkovi
- iTunes Match – Apple podrška
- Bezbednosne beležnice – Apple Docs
- FTS5 – SQLite dokumentacija
- Doppler muzički plejer – App Store
- EXPO FileSystem dokumentacija
- Informacije o programu Apple Developer (7-dnevni buildovi)
- Apple zajednica: Aplikacija za datoteke i MP3 reprodukciju