Izradite izvanmrežne prve mobilne aplikacije bez muke

Alexander Stigsen je suosnivač i izvršni direktor tvrtke Realm.

Istina je univerzalno priznata da korisnik koji posjeduje pametni telefon mora željeti bolju vezu. Unatoč milijardama dolara ulaganja u infrastrukturu i neumoljivih tehnoloških inovacija, nije potrebno više od kratke vožnje da biste primijetili bitnu stvarnost povezane ere: Ne možete pretpostaviti da će mrežna veza biti dostupna svaki put kad to želite. Kao programeri za mobilne uređaje, istinu je koju je prikladno zanemariti.

Izvanmrežna stanja u aplikacijama mogu se zbuniti, ali problem započinje osnovnom i netočnom pretpostavkom - da je izvanmrežno prema zadanim postavkama stanje pogreške. To je imalo smisla kad smo izgradili aplikacije za stolna računala s namjenskim ethernet poveznicama. Nema smisla kada zatvaranje vrata dizala učini aplikaciju potpuno beskorisnom ili kada je razumno očekivati ​​da će se vaša aplikacija koristiti na mjestima koja nemaju pouzdanu staničnu infrastrukturu.

Ne možemo pokrivati ​​svijet pokrivanjem, pa moramo ponuditi alternativu. Prvo moramo razmišljati offline. Moramo dizajnirati aplikacije kako bi bile korisne izvan mreže. Moramo izraditi aplikacije koje u potpunosti iskorištavaju internet kad je dostupan, ali razumijemo da je pristup internetu uvijek privremen. Moramo donijeti pametne odluke o dizajnu koji uključuju izvanmrežna stanja i učiniti ta izvanmrežna stanja razumljivima korisnicima.

Puno se radi na definiranju izvanmrežne prve budućnosti. Realm, tvrtka u kojoj radim, već neko vrijeme gradi platformu u stvarnom vremenu za mobilne izvanmrežne aplikacije. Naša mobilna baza podataka i Realm Mobile Platform olakšavaju stvaranje inteligentnih, izvanmrežnih aplikacija na gotovo bilo kojem mobilnom uređaju. Ljudi iz A List Apart-a dali su ogroman doprinos izvanmrežnoj literaturi, posebno za web aplikacije. A zajednice programera glavnih mobilnih ekosustava provele su mnogo sati nudeći impresivna vlastita rješenja s otvorenim kodom.

Slijedi kratki uvod u to kako možete izraditi izvanmrežnu prvu mobilnu aplikaciju. Pri kraju ću se poslužiti nekim jednostavnim uzorkom koda Swift kako bih pokazao kako izgleda minimalna izvanmrežna aplikacija, ali ovdje ponuđeni principi i problemi relevantni su za sve koji rade na razvoju mobilnih aplikacija.

Dizajn za offline

Prije nego što izradite izvanmrežnu prvu aplikaciju koju ste oduvijek željeli, moramo ponovno posjetiti dizajnerska rješenja koja su imala smisla za stolna računala s vrlo velikom vjerojatnošću da budu na mreži. Ako se vaša aplikacija može nositi s izvanmrežnim i internetskim stanjima, imamo pitanja na koja možemo odgovoriti o tome što može učiniti i kako pokazujemo korisniku što je moguće.

Definirajte što je moguće izvan mreže

Uzmimo za primjer Twitter. Ako niste povezani s internetom i objavite tweet, izvanmrežni prvi Twitter klijent mogao bi proći dva puta. Tweet bi mogao staviti u red čekanja dok ne uspostavi vezu. Ili vam može odbiti dopustiti da tweetujete - čak i ako vam omogućuje da stavite u red drugih radnji, poput omiljenih, kao što to čini Tweetbot.

Zašto bi vas Tweetbot spriječio da tweetujete offline? Možda zato što dok se vratite na mrežu, vaši tweetovi možda više neće biti relevantni. Rješavanje tog problema uključivalo bi izradu novog korisničkog sučelja za popis tweetova koje još niste objavili, ali koje ćete možda trebati urediti ili izbrisati prije nego što se povežu s mrežom. S druge strane, ako ste čuli tweet, malo je vjerojatno da biste ga poništili ako se suočite s više informacija - i puno manje problematično jednostavno naznačiti da je stavljen u red za objavljivanje.

Izvanmrežna aplikacija ne možete učiniti sve što internetska aplikacija može, ali možete je učiniti korisnom.

Dizajnirajte sukobe

Bez obzira na strategiju koju upotrebljavate na stražnjoj strani za usklađivanje promjena, vaša će se aplikacija suočiti s točkom u kojoj imate dva sukobljena dijela podataka. Možda je to zato što se poslužitelj srušio ili zato što ste vi i druga osoba izvršili izvanmrežne promjene i sada ih želite sinkronizirati. Svašta se može dogoditi!

Dakle, predvidite sukobe i nastojte ih riješiti na predvidljiv način. Ponuda izbora. I pokušajte izbjeći sukobe u prvom redu.

Biti predvidljiv znači da vaši korisnici znaju što se može dogoditi. Ako se sukob može pojaviti kada korisnici uređuju na dva mjesta odjednom kad su izvan mreže, tada ih na to treba upozoriti kad su izvan mreže.

Ponuda izbora znači ne samo prihvaćanje zadnjeg pisanja ili spajanje promjena ili brisanje najstarije kopije. To znači dopustiti korisniku da odluči što je prikladno.

Konačno, najbolje rješenje je nikada ne dopustiti da se sukobi uopće razvijaju. Možda to znači izgradnju aplikacije na način da novi i čudni podaci iz mnogih izvora ne dovedu do sukoba, već se prikazuju točno onako kako biste željeli. To bi moglo biti teško izvesti u aplikaciji za pisanje koja ide na mrežu i izvan nje, ali zajednička aplikacija za crtanje može se oblikovati tako da crtežu doda nove staze kad god se sinkronizira.

Budite eksplicitni

Jedna je stvar definirati što korisnik može raditi izvan mreže. Potpuno drugi problem uključuje donošenje tih odluka razumljivim vašim korisnicima. Neuspjeh uspješnog komuniciranja o stanju vaših podataka i povezanosti ili dostupnosti zadanih značajki, ravan je neuspjehu kada ste uopće izgradili izvanmrežnu prvu aplikaciju.

Dijeljena aplikacija za bilježenje ilustrira problem. Ako odete izvan mreže, ali očekujete da suradnici nastave uređivati ​​aplikaciju u vašoj odsutnosti, nije dovoljno jednostavno dopustiti korisniku da nastavi tipkati dok ne bude sretan. Kad se ponovno povežu, iznenadit će ih sukobi koji su se razvili.

Umjesto toga, pomozite svom korisniku da donese ispravnu odluku. Ako primijetite da je veza s poslužiteljem prekinuta jer gornja traka vaše aplikacije mijenja boju, znate što bi moglo uslijediti: spajanje sukoba! To bi većinu vremena moglo biti u redu, a korisničko sučelje vaše aplikacije može pomoći u rješavanju neočekivanih sukoba kada se vratite na mrežu. Ali ako izgubite vezu kada više ljudi uređuje vašu aplikaciju, ne bi li bilo korisno znati da je rizik od sukoba mnogo veći? “Izgubili ste vezu, ali drugi su uređivali. Nastavak uređivanja mogao bi izazvati sukobe. " Korisnik može nastaviti, ali zna rizik.

Lako je beskrajno pisati o dizajnerskim problemima i rješenjima, ali prije nego što se previše udaljimo od alata koje ćemo morati koristiti, možda bi bilo korisno vidjeti kako je to izgraditi izvanmrežnu prvu mobilnu aplikaciju.

Izradite izvanmrežnu prvu aplikaciju s Realm-om

Arhitektura osnovne izvanmrežne aplikacije nije fensi. Potreban vam je način za zadržavanje podataka u aplikaciji (pomoću baze podataka na uređaju), protokol za komunikaciju s poslužiteljem (uključujući kôd za serializaciju i deserializaciju, ako je potrebno) i poslužitelj na kojem će sinhronizirani podaci živjeti kako bi se mogli podijeljeno onome tko ima dozvolu.

Prvo ću vas provesti kroz početak rada s Realm Mobile Databaseom u aplikaciji za iOS (iako kôd u Android aplikaciji ne bi izgledao puno drugačije). Tada ću predstaviti strategiju za serializaciju i deserializaciju koda koji dobijete od poslužitelja i pohranite u vašu lokalnu bazu podataka Realma. Na kraju ću vam pokazati kako to sve skupa raditi u zajedničkoj aplikaciji s popisom obveza koja se sinkronizira u stvarnom vremenu.

Baza podataka Mobile Realm

Lako je započeti s Realmom. Instalirate Realm Mobile Database, a zatim definirate svoju shemu izradom klasa. Budući da je Realm baza podataka objekata, to je zaista jednostavno poput izrade klasa, instanciranja nekih objekata i prosljeđivanja tih objekata u writeblok da bi se nastavili na disku. Nije potrebna serializacija ili ORM, plus je brža od Appleovih temeljnih podataka.

Evo srži našeg modela i najosnovnije moguće liste obveza (koju biste morali prekompajlirati svaki put kad biste željeli napraviti novi zadatak):

import RealmSwift

class Task: Object {

   dynamic var name

}

class TaskList: Object {

   let tasks = List()

}

let myTask = Task()

myTask.task

let myTaskList = TaskList()

myTaskList.tasks.append(myTask)

let realm = Realm()

try! realm.write{

            realm.add([myTask, myTaskList])

}

Odatle ne treba puno za izgradnju potpuno funkcionalnije aplikacije oko TableViewController:

import UIKit

import RealmSwift

class TaskListTableViewController: UITableViewController {

   var realm = try! Realm()

   var taskList = TaskList()

   override func viewDidLoad() {

       super.viewDidLoad()

       print(Realm.Configuration.defaultConfiguration.fileURL!)

       // Here, you could replace self.taskList with a previously saved TaskList object

       try! realm.write {

           realm.add(self.taskList)

       }

       // add navbar +

       navigationItem.setRightBarButton(UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(displayTaskAlert)), animated: false)

   }

   func displayTaskAlert() {

       // make and display an alert that’ll take a name and make a task.

       let alert = UIAlertController(title: “Make a task”, message: “What do you want to call it?”, preferredStyle: UIAlertControllerStyle.alert)

       alert.addTextField(configurationHandler: nil)

       alert.addAction(UIAlertAction(title: “Cancel”, style: UIAlertActionStyle.cancel, handler: nil))

       alert.addAction(UIAlertAction(title: “Create Task”, style: UIAlertActionStyle.default, handler: { (action) in

           let task = Task()

           task.name = (alert.textFields?[0].text)!

           try! self.realm.write {

               self.realm.add(task)

               self.taskList.tasks.append(task)

           }

           self.tableView.reloadData()

       }))

       self.present(alert, animated: true, completion: nil)

   }

   override func didReceiveMemoryWarning() {

       super.didReceiveMemoryWarning()

   }

   override func numberOfSections(in tableView: UITableView) -> Int {

       return 1

   }

   override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

       return self.taskList.tasks.count

   }

   override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

       let cell = tableView.dequeueReusableCell(withIdentifier: “reuseIdentifier”, for: indexPath)

       cell.textLabel?.text = self.taskList.tasks[indexPath.row].name

       return cell

   }

}

To je sve što je potrebno za početak! Realmove zbirke i obavijesti o objektima mogu postati pametniji, tako da možete inteligentno ponovno učitati tableViewkada se objekt doda ili izbriše, ali za sada imamo upornost - temelj izvanmrežne prve aplikacije.

Serijalizacija i deserializacija

Izvanmrežna prva aplikacija nije velika izvanmrežna aplikacija, osim ako se također ne može povezati s mrežom, a dohvaćanje podataka iz i iz Realma može biti pomalo nezgodno.

Prije svega, presudno je usklađivanje sheme vašeg klijenta sa shemom vašeg poslužitelja. S obzirom na to kako funkcionira većina pozadinskih baza podataka, to će vjerojatno uključivati ​​dodavanje polja primarnog ključa u vašu klasu Realm, jer objekti Realma po defaultu nemaju primarni ključ.

Nakon što se vaša shema dobro podudara, potreban vam je način za deserializaciju podataka koji dolaze s poslužitelja u Realm i za serializaciju podataka u JSON za vraćanje na poslužitelj. Najjednostavnije je to odabrati biblioteku za mapiranje omiljenih modela i pustiti je da podigne teške ruke. Swift ima Argo, Decodable, ObjectMapper i Mapper. Sada kada dobijete odgovor od poslužitelja, jednostavno dopustite da ga mapper modela dekodira u izvorni RealmObject.

Ipak, nije tako sjajno rješenje. Još uvijek morate napisati tonu mrežnog koda da biste prije svega JSON sigurno i sigurno odveli na vaš poslužitelj i s vašeg poslužitelja, a kod koda za mapiranje vašeg modela trebat će prepraviti i ispraviti pogreške u bilo kojem trenutku kad se vaše sheme promijene. Trebao bi postojati bolji način, a mi mislimo da je Realm Mobile Platform upravo to.

Rad s mobilnom platformom Realm

Realm Mobile Platform (RMP) pruža vam sinkronizaciju u stvarnom vremenu, tako da se možete usredotočiti na izgradnju mobilne aplikacije, a ne u borbi za nagovor poslužitelja i aplikacije. Jednostavno uzmete gore navedeni model Realm, dodate RMP-ovu provjeru autentičnosti korisnika i pustite da RMP brine o sinkronizaciji podataka između poslužitelja i područja vaše aplikacije. Tada jednostavno nastavljate raditi s izvornim Swift objektima.

Da biste započeli, preuzmite i instalirajte Realm Mobile Platform MacOS paket, koji vam omogućuje da instalaciju poslužitelja Realm Object Server pokrenete na vašem Macu vrlo brzo. Zatim ćemo dodati nekoliko stavki u našu aplikaciju popisa obveza kako bismo se povezali s poslužiteljem Realm Object.

Kad završite s gore navedenim uputama za instalaciju, trebali biste pokrenuti poslužitelj i administratora na //127.0.0.1:9080. Zapamtite te vjerodajnice i vratit ćemo se našem Swift kodu.

Prije nego što napišemo bilo koji kod, moramo napraviti dvije male promjene u projektu. Prvo moramo otići do ciljanog uređivača naše aplikacije u Xcodeu, a na kartici Capabilities omogućiti prekidač Keychain Sharing.

Tada ćemo morati dopustiti mrežne zahtjeve koji nisu TLS. Idite na datoteku Info.plist projekta i dodajte sljedeće u oznake:

NSAppTransportSecurity

   NSAllowsArbitraryLoads