Askeleet, matka, kalorit, syke ja uni on haettava käyttäjän alustalta (Androidin Android Health Connect, iOS:n Apple HealthKit) terveys- ja ravitsemussovellukseen – ja esitettävä yhtenä selkeänä, kaksoiskappaleet poistettuna päiväprofiilina. Näiden kahden API:n välillä on hyvin vähän yhtäläisyyksiä: erilliset lukumekaniikat, erilaiset valtuutusjärjestelmät ja erilaiset tietorakenteet. Rakensimme mobiilisynkronointikerroksen, joka saa ne näyttämään yhtenäiseltä.
Haaste
- Kaksi natiivia API:a, jotka eivät sovi mistään. Apple HealthKit palauttaa päivittäiset aggregaatit callbackien kautta; Health Connect palauttaa raakoja, sivutettuja näytteitä runsaalla lähdemetadatalla. Samat konseptit, täysin erilaiset muodot – ja sovelluksen täytyi normalisoida molemmat yhdeksi skeemaksi.
- Kaksoislaskenta on oletus. Puhelin, älykello ja kolmannen osapuolen sovellus voivat kaikki raportoida samat 8 000 askelta. Niiden naiivi yhteenlaskenta paisuttaa jokaista mittaria. Sovelluksen täytyi tunnistaa päällekkäiset lähteet ja laskea jokainen todellinen aktiviteetti vain kerran.
- Akku ja verkko eivät voi maksaa tuoreudesta. Terveystiedot muuttuvat koko päivän, mutta koko historian lukeminen jokaisella synkronoinnilla kuluttaisi akun ja kuormittaisi mobiiliyhteydet. Synkronointitiheyden täytyi pysyä kevyenä, mutta silti tuntua reaaliaikaiselta.
Käyttöoikeudet voivat olla hämmentäviä. Kymmeniä tietotyyppejä, kaksi käyttöoikeusmallia, taustaluku-rajoituksia ja käyttäjiä, jotka myöntävät joitakin oikeuksia mutta eivät toisia – kaikki, mitä sovelluksen on käsiteltävä kaatumatta.
Ratkaisumme
Rakensimme kolmikerroksisen synkronoinnin: ohut natiivikerros lukee kunkin alustan API:n, laitteessa suoritettava normalisointikerros poistaa kaksoiskappaleet ja tiivistää tiedot päivittäisiksi yhteenvedoiksi, ja taustajärjestelmä tallentaa ja yhdistää ne yhdeksi luotetuksi kirjanpitokansioksi. Asiakas ei koskaan lähetä raakoja näytteitä – se lähettää puhtaita, aikavyöhykekorjattuja päivittäisiä koosteita.

Arkkitehtuuri
- iOS lukee Apple HealthKitia react-native-health-kirjaston kautta; Android lukee Health Connectia react-native-health-connect-kirjaston kautta.
- Laitteessa tapahtuva normalisointi muuntaa molempien alustojen ulostulon yhdeksi skeemaksi ja poistaa kaksoiskappaleet ennen kuin mitään lähtee puhelimesta.
- Synkronoinnin käynnistimet — 30 päivän historia ensimmäisellä käynnistyksellä, sitten kevyet yhden päivän inkrementaaliset lukuoperaatiot 10 minuutin välein ja joka kerta kun sovellus jatkaa toimintaansa.
- Siirto — normalisoidut päivittäiset koosteet POSTataan pääpalvelimen osoitteeseen /user-health/system-activity, joka välittää ne (käyttäjätunnuksella + aikavyöhykkeellä) terveys-mikropalveluun.
- Pysyvyys — kukin lähde/päivä tallennetaan idempotentisti nimellä HealthSystemAggregate; MongoDB change stream sovittaa sen sitten päiväkohtaiseksi HealthLedgeriksi.
Expo / React Native hallittu työnkulku natiivien HealthKit- ja Health Connect -moduulien kanssa.
Avainominaisuudet
- Yksi normalisointisopimus kahdelle API:lle. Alustakohtaiset lukijat syöttävät yhteen formatHealthData-vaiheeseen, joka tuottaa saman muodon lähteestä riippumatta – joten taustajärjestelmä ja käyttöliittymä eivät koskaan haaraudu iOS:n ja Androidin välillä.
2. Maksimiin perustuva kaksoiskappaleiden poisto laitteella. Kussakin lähteessä päivän lukemat summataan; sitten päivittäinen arvo on Math.max() lähteiden yli (kalorit avaimella source|deviceType), joten yhdestä laitteesta tulevat useat lukemat kertyvät, kun taas samasta päivästä raportoiva kello ja puhelin eivät kerrytä kaksinumeroista summaa:
// Sum readings within each source, then take the max ACROSS sources dateSourceMap[date][source] += entry.count; const totalSteps = Math.ceil(Math.max(...Object.values(dateSourceMap[date]))); |
3.Oikea lukustrategia kullekin alustalle. Health Connect -lukemat ovat sivutettuja pageToken-silmukalla (1 000 tietuetta/sivu); HealthKitin päivittäiset aggregaatit käydään läpi päivä kerrallaan. Jokainen erikoisuus sisältyy omaan lukijaan, näkymättömänä muulle sovellukselle.
4. Synkronointitiheys, joka huomioi akun. Täysi 30 päivän takautuva täyttö suoritetaan vain kerran (suojattuna ensimmäisen kutsun lipulla); sen jälkeen jokainen synkronointi hakee vain yhden päivän – nopeasti mobiiliverkossa, edullisesti virrankulutuksen osalta.
5. Aikavyöhykekorjattu päivittäinen ryhmittely. Näytteet ryhmitellään YYYY-MM-DD-avaimiin käyttäjän omalla aikavyöhykkeellä, joten klo 23:n harjoitus päätyy oikealle päivälle riippumatta siitä, missä palvelin sijaitsee.
6. Idempotentit taustajärjestelmän kirjoitukset. Kukin kooste päivittää tai lisää tiedot avaimella (userId, deviceId, source, date) – saman päivän uudelleenlähetys on no-op-operaatio, mikä tekee uudelleenyrityksistä ja päällekkäisistä synkronoinneista turvallisia.
7. Rehellinen vikatilanteen käsittely. Puuttuvat käyttöoikeudet, tyhjät lukemat ja Health Connectin nopeusrajoitusvirheet havaitaan ja tuodaan esiin selkeästi – tyhjä päivä ei koskaan kaada synkronointia, ja käyttäjä saa selkeän ilmoituksen hiljaisen virheen sijaan.
Tulokset
- Yksi, yhtenäinen terveysprofiili iOS:n ja Androidin välillä – alustojen välinen ero on näkymätön muulle sovellukselle.
- Päällekkäiset laite-/sovelluslähteet on deduplikoitu, joten askeleet ja kalorit heijastavat todellisuutta paisutettujen summien sijaan.
- Kevyet inkrementaaliset synkronoinnit pitävät tiedot tuoreina kuluttamatta akkua tai mobiilidataa.
Aikavyöhykekorjatut, idempotentit kirjoitukset tarkoittavat, että jokainen mittari päätyy oikealle päivälle, eivätkä uudelleenyritykset koskaan vioita tietoa.
Teknologiapino
React Native (Expo) · react-native-health (HealthKit) · react-native-health-connect · NestJS · MongoDB · MongoDB Change Streams · moment-timezone

