In mijn Easy Native Development met Expo-post, hoorde je hoe Expo het gemakkelijker maakt voor beginners om apps te maken met React Native. Je hebt ook geleerd dat Expo ontwikkelaars toestaat om met het ontwikkelen van React Native-apps sneller aan de slag te gaan omdat Android Studio, Xcode of andere ontwikkeltools niet meer hoeven te worden opgezet.
Maar zoals je ook hebt gezien, ondersteunt Expo niet alle native functies die een app nodig heeft. Hoewel het Expo-team altijd bezig is om meer native-functionaliteit te ondersteunen, is het een goed idee om te leren hoe je een bestaand Expo-project converteert naar een standaard native project, zodat je gemakkelijk kunt overstappen als de behoefte zich voordoet.
Dus, in deze tweedelige serie, bekijken we hoe we dat moeten doen. In het eerste deel van de serie leerde je de basisbegrippen van ExpoKit. In dit bericht gaan we verder waar we zijn gebleven door de app daadwerkelijk los te koppelen aan ExpoKit en door te gaan met het coderen van de app voor het delen van locaties.
Om de ExpoKit te verwijderen, moet je eerst de app.json en package.json bestanden.
In de app.json bestand, zorg ervoor dat een naam
is vastgesteld. De platforms
moeten de platforms zijn waar je naar wilt bouwen.
"expo": "name": "ocdmom", "platforms": ["ios", "android"],
Als u wilt bouwen voor iOS, moet u het ios
keuze:
"ios": "bundleIdentifier": "com.ocd.mom",
Als u Android wilt ondersteunen, geeft u ook de volgende optie op:
"android": "package": "com.ocd.mom"
Er zijn andere opties die zijn voorgevuld door de exp
opdrachtregelprogramma toen het project werd gemaakt. Maar de enige belangrijke zijn de bundleIdentifier
voor iOS en pakket
voor Android. Dit zijn de unieke ID's voor de app zodra ze zijn gepubliceerd in de Apple- of Play Store. Onthechten vereist deze details omdat het de native code genereert voor de app die op een apparaat moet worden uitgevoerd. U kunt meer informatie vinden over de verschillende configuratie-opties voor de app.json bestand in de Expo-documentatie.
U kunt de volledige inhoud van het bestand in de GitHub-repo bekijken.
Open vervolgens de package.json bestand en voeg de naam van het project toe:
"naam": "ocdmom"
Dit zou de naam moeten zijn die u gebruikte toen u het project maakte met exp init
. Het is heel belangrijk dat ze hetzelfde zijn, omdat de naam
u specificeert in de package.json wordt gebruikt bij het compileren van de app. Inconsistenties in deze naam zullen een fout veroorzaken.
Nu zijn we klaar om los te koppelen aan ExpoKit. Voer de volgende opdracht uit in de hoofdmap van de projectdirectory:
ontkoppelen
Hiermee worden de native Expo-pakketten voor Android en iOS lokaal gedownload.
U zou een uitvoer moeten zien die lijkt op het volgende als het lukt:
Als u implementeert op iOS, moet u de nieuwste versie van Xcode installeren. Op het moment van schrijven van deze tutorial is de nieuwste versie 9. Installeer CocoaPods vervolgens door te executeren sudo gem installeer cocoapods
. Hiermee kunt u de native iOS-afhankelijkheden van het project installeren. Als dat is gebeurd, navigeert u naar de ios map van het project en voer uit pod installeren
om alle native afhankelijkheden te installeren.
Nu we hebben verwijderd, kunnen we nu native-pakketten installeren, net als in een standaard React Native-project.
Voor deze app hebben we de React Native Background Timer- en Pusher-pakketten nodig.
Installeer eerst het Pusher-pakket omdat het eenvoudiger is:
npm install - save pusher-js
Dit stelt ons in staat om te communiceren met de Pusher-app die u eerder hebt gemaakt.
Installeer vervolgens de React Native Background Timer. Hierdoor kunnen we periodiek code uitvoeren (zelfs wanneer de app op de achtergrond staat) op basis van een specifiek interval:
npm install - sla react-native-achtergrond-timer op
In tegenstelling tot het Pusher-pakket, vereist dit dat een native library (iOS of Android) aan de app wordt gekoppeld. Het uitvoeren van de volgende opdracht doet dat voor u:
reactieve koppeling
Als het eenmaal klaar is, zou het ook de module moeten initialiseren android / app / src / main / host / exp / exponent / MainApplication.java. Maar controleer om te controleren of het volgende in dat bestand bestaat:
import com.ocetnik.timer.BackgroundTimerPackage; // bekijk deze openbare lijstgetPackages () Arrays retourneren. asList (nieuw BackgroundTimerPackage () // ook controleren);
Als u voor iOS bouwt, opent u de Podfile binnen in de ios map en zorg ervoor dat het volgende wordt toegevoegd vóór de post_install
verklaring:
pod 'react-native-background-timer',: path => '... / node_modules / react-native-background-timer'
Als dat is gebeurd, voer je uit pod installeren
binnen in de ios
map om de native module te installeren.
Voor Android wordt dit al automatisch gedaan wanneer u de app uitvoert met Android Studio.
Als u voor Android bouwt, opent u het Android-manifestbestand (android / app / src / main / AndroidManifest.xml) en zorg ervoor dat de volgende machtigingen zijn toegevoegd:
Hiermee kunnen we toestemming vragen aan Pusher voor toegang tot internet en Expo om de huidige locatie van de gebruiker op Android-apparaten te krijgen.
We zijn nog niet klaar, maar het is beter om de app nu uit te voeren, zodat u al kunt zien of deze werkt of niet. Op die manier kunt u de wijzigingen ook bekijken tijdens het ontwikkelen van de app.
De eerste stap bij het uitvoeren van de app is om uit te voeren exp start
vanuit de hoofdmap van het project. Hiermee wordt de ontwikkelserver gestart, zodat elke wijziging die u aanbrengt in de broncode wordt weergegeven in het app-voorbeeld.
Als u voor Android bouwt, opent u Android Studio en selecteert u Open een bestaand Android Studio-project. Selecteer de. In de indexselectie die verschijnt android map binnen het Expo-project. Nadat u de map hebt geselecteerd, moet deze de bestanden in die map indexeren. Op dat moment zou u nu in staat moeten zijn om het project opnieuw op te bouwen door te selecteren Build> Rebuild Project vanuit het topmenu. Zodra dat is gebeurd, start u de app door te selecteren Uitvoeren> Run 'app'.
Android Studio kan de app uitvoeren op elk Android-apparaat dat is aangesloten op uw computer, op een van de emulators die u hebt geïnstalleerd via Android Studio of via Genymotion (Android Studio detecteert automatisch een actieve emulatie-instantie). Voor deze app raad ik je aan de Genymotion-emulator te gebruiken, omdat deze een leuke GPS-emulatie-widget heeft waarmee je de locatie kunt wijzigen via een Google Maps-interface:
(Als u problemen ondervindt bij het uitvoeren van de app op uw apparaat, moet u deze Stack Overflow-vraag bekijken om ervoor te zorgen dat Android Studio uw apparaat herkent.)
Zodra dat is gebeurd, opent u de ios /ocdmom.xcworkspace bestand met Xcode. Zodra Xcode klaar is met het indexeren van de bestanden, zou je in staat moeten zijn om die grote afspeelknop te raken en het zal de app automatisch uitvoeren op je geselecteerde iOS-simulator.
Met Xcode kun je ook de locatie bespotten, maar alleen als je de app bouwt om in de simulator te draaien. Door een wijziging aan te brengen in de code en de ontwikkelserver de app te laten vernieuwen, wordt de locatie niet echt gewijzigd. Om de locatie te wijzigen, klikt u op het verzendpictogram en selecteert u de locatie die u wilt gebruiken:
Nu zijn we klaar om door te gaan met het schrijven van de code voor de app. Deze keer zullen we de functionaliteit toevoegen om wat code uit te voeren terwijl de app op de achtergrond staat.
Importeer het Pusher- en Background Timer-pakket dat u eerder hebt geïnstalleerd:
importeer BackgroundTimer van 'react-native-background-timer'; import Pusher van 'pusher-js / react native';
Stel de waarde in voor de Google API-sleutel van het Google-project dat u eerder hebt gemaakt:
const GOOGLE_API_KEY = 'UW API-SLEUTEL VAN GOOGLE PROJECT';
Gebruik de API voor locaties en rechten van Expo:
const Locatie, Toestemmingen = Expo;
De API's van Expo werken platformoverschrijdend - dit is niet anders dan een standaard React Native-project waarbij je een pakket zoals React Native Permissies moet installeren om toegang te krijgen tot een permissies-API die platformonafhankelijk werkt.
Stel vervolgens het interval (in milliseconden) in dat de code voor het volgen van de huidige locatie van de gebruiker moet uitvoeren. In dit geval willen we dat het elke 30 minuten wordt uitgevoerd. Merk op dat we in de onderstaande code de waarde van de gebruiken location_status
variabele om te controleren of de toestemming voor toegang tot de huidige locatie van de gebruiker al dan niet is toegekend. We zullen de waarde van deze variabele later instellen, zodra het onderdeel is aangekoppeld:
var interval_ms = 1800 * 100; // 1800 seconden = 30 minuten, maal 100 om te zetten in milliseconden var location_status = null; // of toegang tot de locatie van de gebruiker is toegestaan of niet BackgroundTimer.runBackgroundTimer (() => // voer de achtergrondtaak uit als (location_status == 'granted') // als toestemming voor toegang tot de locatie wordt verleend door de gebruiker / / volgende: code toevoegen om de huidige locatie van de gebruiker te verkrijgen, interval_ms);
Haal de huidige locatie op met behulp van Expo's Location API:
Location.getCurrentPositionAsync (// de gebruikerscoördinaten inschakelenHighAccuracy: true // inschakelen ophalen van locatie met hoge nauwkeurigheid) .then ((res) => let latitude, longitude = res.coords; // extract the latitude and lengtewaarden // volgende: voeg code toe om het adres te krijgen op basis van de coördinaten);
Gebruik vervolgens de Google Maps Geocoding API om een verzoek in te dienen voor het omgekeerde geocoderingseindpunt door de waarden voor lengte- en breedtegraden in te voeren. Hierdoor wordt een opgemaakt adres geretourneerd op basis van die coördinaten:
ophalen ('https://maps.googleapis.com/maps/api/geocode/json?latlng=$ latitude, $ longitude & key = $ GOOGLE_API_KEY') .then ((response) => reactie. json ()) .then ((responseJson) => laat addr = responseJson.results [0] .formatted_address; // next: stuur de locatie met Pusher) .catch ((error) => console.error (error ););
De volgende stap is om de locatie met behulp van Pusher te verzenden. Later gaan we de server maken die zal dienen als het authenticatie-eindpunt en tegelijkertijd de pagina weergeven die de huidige locatie van de gebruiker laat zien.
Werk de constructor bij om een standaardwaarde in te stellen voor de Pusher-instantie:
constructor () / * de code voor het genereren van unieke code van eerder * / this.pusher = null;
Wanneer het onderdeel is aangekoppeld, willen we Pusher initialiseren. U kunt nu de Pusher API-sleutel en cluster leveren vanuit de instelling van de Pusher-app die u eerder hebt gemaakt:
componentWillMount () this.pusher = nieuwe Pusher ('YOUR PUSHER APP KEY', authEndpoint: 'UW AUTH-SERVER ENDPOINT (MOET LATER WORDEN TOEGEVOEGD)', cluster: 'YOUR PUSHER CLUSTER', versleuteld: waar // of de verbinding wordt versleuteld of niet. Dit vereist https indien ingesteld op true);
Vervolgens kunt u nu de code toevoegen voor het verzenden van de huidige locatie. In Pusher wordt dit gedaan door de op gang brengen()
methode. Het eerste argument is de naam van de gebeurtenis die wordt geactiveerd en het tweede argument is een object dat de gegevens bevat die u wilt verzenden.
Later, op de server, abonneren we ons op hetzelfde kanaal waarop we ons abonneren zodra het onderdeel is aangekoppeld. Dan binden we ons aan de client-locatie
gebeurtenis, zodat elke keer dat deze ergens wordt geactiveerd, de server ook op de hoogte wordt gesteld (hoewel alleen wanneer de pagina die wordt weergegeven ook op hetzelfde kanaal is geabonneerd):
fetch (...) .then (...) .then ((responseJson) => let addr = responseJson.results [0] .formatted_address; current_location_channel.trigger ('client-location', addr: addr, lat: latitude, lng : lengtegraad);) .catch (...);
De enige keer dat we toestemming vragen om toegang te krijgen tot de huidige locatie van de gebruiker, is wanneer het onderdeel is aangekoppeld. We zullen dan het location_status
op basis van de selectie van de gebruiker. De waarde kan worden "verleend" of "geweigerd".
Vergeet niet dat de code voor het controleren van de huidige locatie van de gebruiker periodiek wordt uitgevoerd. Dit betekent dat de nieuwe waarde van de location_status
variabele zal ook worden gebruikt op een later tijdstip wanneer de functie wordt uitgevoerd. Daarna willen we ons ook abonneren op het Pusher-kanaal waar de locatie-updates worden verzonden:
componentDidMount () try Permissions.askAsync (Permissions.LOCATION) .then ((status) => location_status = status;); catch (error) console.log ('err:', error); // subscribe to the Pusher channel current_location_channel = this.pusher.subscribe ('private-current-location-' + this.state.unique_code);
Nu zijn we klaar om de server te maken. Maak eerst je werkdirectory (ocdmom-server) buiten de projectdirectory van de app. Navigeer in die map en voer uit npm init
. Druk gewoon op invoeren totdat het de package.json het dossier.
Installeer vervolgens de pakketten die we nodig hebben:
npm install - save express body-parser pusher
Hier is een overzicht van wat elk pakket doet:
uitdrukken
: gebruikt voor het maken van een server. Dit is verantwoordelijk voor het bedienen van de trackingpagina en voor het beantwoorden van het auth-eindpunt.body-parser
: Express middleware die de hoofdtekst van het verzoek parseert en beschikbaar maakt als een JavaScript-object. pusher
: gebruikt voor communicatie met de Pusher-app die u eerder hebt gemaakt.Zodra dat is gebeurd, is uw package.json bestand zou er nu als volgt uit moeten zien:
"name": "ocdmom-server", "version": "1.0.0", "description": "", "main": "server.js", "scripts": "test": "echo \ "Fout: geen test opgegeven \" && exit 1 "," start ":" node server.js "," author ":" "," license ":" ISC "," dependencies ": " body-parser " : "^ 1.18.2", "express": "^ 4.16.2", "pusher": "^ 1.5.1"
Maak een server.js bestand en importeer de pakketten die we zojuist hebben geïnstalleerd:
var express = require ('express'); var bodyParser = require ('body-parser'); var Pusher = require ('pusher');
Configureer de server om de te gebruiken body-parser
pakket en stel de openbaar map als de map met statische bestanden:
var app = express (); app.use (bodyParser.json ()); // middleware instellen om het aanvraaglichaam te parseren naar JavaScript-object app.use (bodyParser.urlencoded (extended: false)); // voor het parseren van URL-gecodeerde request body app.use (express.static ('public')); // geef de map op waar de statische bestanden zoals css, JavaScript en afbeeldingsbestanden leven
Initialiseer Pusher. De hier geleverde waarden komen uit de omgevingsvariabelen. We zullen die later toevoegen wanneer we de server inzetten:
var pusher = new Pusher (appId: process.env.APP_ID, key: process.env.APP_KEY, secret: process.env.APP_SECRET, cluster: process.env.APP_CLUSTER,);
Bedien de volgpagina wanneer de basis-URL wordt geopend:
app.get ('/', functie (req, res) res.sendFile (__ dirname + '/public/tracker.html'););
Maak vervolgens de route om te reageren op verzoeken om het authenticatie-eindpunt. Dit wordt elke keer geraakt wanneer de app de verbinding met Pusher initialiseert en ook wanneer de trackingpagina wordt geopend. Wat dit doet, is de gebruiker authenticeren, zodat deze direct vanaf de clientzijde met de Pusher-app kan communiceren.
Merk op dat dit niet echt beveiligingsmaatregelen bevat. Dit betekent dat iedereen gewoon een verzoek kan indienen bij uw auth-eindpunt als deze toegang heeft tot uw Pusher-app-sleutel. In een productie-app wilt u meer robuuste beveiliging!
app.post ('/ pusher / auth', functie (req, res) var socketId = req.body.socket_id; var channel = req.body.channel_name; var auth = pusher.authenticate (socketId, channel); var app_key = req.body.app_key; var auth = pusher.authenticate (socketId, channel); res.send (auth););
Laat de server ten slotte luisteren naar de poort die is opgegeven in de omgevingsvariabelen. Standaard is dit poort 80, maar we stellen deze ook in als alternatieve waarde voor het geval deze niet bestaat:
var port = process.enTIEPORT || 80; app.listen (poort);
Op de volgpagina wordt een kaart weergegeven die telkens wordt bijgewerkt client-locatie
gebeurtenis wordt geactiveerd vanuit de app. Vergeet niet om uw Google API-sleutel op te geven:
OCDMom Tracker
Maak vervolgens een public / js / tracker.js bestand en voeg het volgende toe:
function getParameterByName (name, url) if (! url) url = window.location.href; name = name.replace (/ [\ [\]] / g, "\\ $ &"); var regex = new RegExp ("[? &]" + naam + "(= ([^ & #] *) | & | # | $)"), results = regex.exec (url); als (! resultaten) null retourneren; als (! resultaten [2]) terugkeren "; return decodeURIComponent (results [2] .replace (/ \ + / g," "));
De bovenstaande functie haalt de queryparameter uit de URL. De unieke code (die wordt weergegeven in de app) moet worden opgenomen als een queryparameter wanneer de basis-URL van de server wordt gebruikt in een browser. Dit stelt ons in staat om de locatie van de gebruiker bij te houden omdat deze ons zal inschrijven op hetzelfde kanaal als waarop de app zich heeft geabonneerd.
Start vervolgens Pusher. De code lijkt eerder op de code op de server. Het enige verschil is dat we alleen de app-sleutel van de opdringer, het authenticatie-eindpunt en de cluster moeten specificeren:
var pusher = new Pusher ('YOUR PUSHER APP KEY', authEndpoint: 'YOUR PUSHER AUTH ENDPOINT', cluster: 'YOUR PUSHER CLUSTER', versleuteld: true);
Controleer of de code
wordt geleverd als een queryparameter en abonneert zich alleen op het push-kanaal als het wordt geleverd:
var channel = null; if (getParameterByName ('code') == null) alert ('Zorg ervoor dat de code wordt geleverd als een queryparameter en ververs dan de pagina.'); else channel = pusher.subscribe ('private-current-location-' + getParameterByName ('code'));
Voeg de functie toe voor het initialiseren van de kaart. Hierdoor wordt de kaart weergegeven samen met een markering die naar de standaardlocatie verwijst die we hebben opgegeven:
var map = null; var marker = null; function initMap () var myLatLng = // stel de standaardlocatie in die wordt weergegeven op de kaart lat: -25.363, lng: 131.044; map = new google.maps.Map (document.getElementById ('map'), zoom: 16, center: myLatLng); marker = new google.maps.Marker (position: myLatLng, map: map);
Bind met de client-locatie
evenement. De callback-functie wordt elke keer uitgevoerd als de app a activeert client-locatie
gebeurtenis die dezelfde unieke code heeft als de door de gebruiker als queryparameter opgegeven:
if (channel) channel.bind ('client-location', function (data) console.log ('message received:', data); var position = new google.maps.LatLng (data.lat, data.lng ); // maak een nieuw objectpositieobject voor Google maps // stel dit in als de positie voor de markering en de kaartmarkering.setPosition (positie); map.setCenter (positie););
Voeg vervolgens de stijlen voor de volgpagina toe (public / css / style.css):
#map height: 100%; html, body height: 100%; marge: 0; opvulling: 0;
We zullen Nu gebruiken om de server te implementeren. Het is gratis voor open-sourceprojecten.
Installeer nu wereldwijd:
npm nu installeren
Nadat het is geïnstalleerd, kunt u de aanmeldingsgegevens van de Pusher-app nu als geheimen toevoegen. Zoals eerder vermeld, is Now gratis voor open-sourceprojecten. Dit betekent dat zodra de server is geïmplementeerd, de broncode beschikbaar is op de / _src
pad. Dit is niet echt goed omdat iedereen ook de inloggegevens van je Pusher-app kan zien. Dus wat we zullen doen is ze als een geheim toevoegen, zodat ze als een omgevingsvariabele toegankelijk zijn.
Herinner de process.env.APP_ID
of process.env.APP_KEY
van de servercode eerder? Die worden ingesteld als omgevingsvariabelen via geheimen. pusher_app_id
is de naam die aan het geheim is toegewezen, en YOUR_PUSHER_APP_ID
is de ID van je Pusher-app. Voer de volgende opdrachten uit om uw Pusher-app-inloggegevens als geheimen toe te voegen:
nu geheim toevoegen pusher_app_id YOUR_PUSHER_APP_ID nu geheim toevoegen pusher_app_key YOUR_PUSHER_APP_KEY nu geheim toevoegen pusher_app_secret YOUR_PUSHER_APP_SECRET nu geheim toevoegen pusher_app_cluster YOUR_PUSHER_APP_CLUSTER
Zodra u deze hebt toegevoegd, kunt u nu de server implementeren. APP_ID
is de naam van de omgevingsvariabele, en pusher_app_id
is de naam van het geheim dat u wilt openen:
nu -e APP_ID = @ pusher_app_id -e APP_KEY = @ pusher_app_key -e APP_SECRET = @ pusher_app_secret APP_CLUSTER = @ pusher_app_cluster
Zo ziet het eruit zodra het klaar is met de implementatie. De URL die wordt geretourneerd is de basis-URL van de server:
Kopieer die URL naar de App.js bestand en sla de wijzigingen op:
this.pusher = nieuwe Pusher ('UW DRUKPERSEN APP TOETS', authEndpoint: 'https: // BASE-URL-OF-YOUR-SERVER / pusher / auth', cluster: 'YOUR PUSHER APP CLUSTER', versleuteld: true );
Op dit moment zou de app nu volledig functioneel moeten zijn.
Dat is het! In deze tweedelige serie heb je geleerd hoe je een bestaand Expo-project kunt losmaken van ExpoKit. ExpoKit is een goede manier om een aantal tools te gebruiken die het Expo-platform biedt, terwijl je app al is omgezet naar een standaard native project. Hiermee kunt u bestaande native modules voor React Native gebruiken en uw eigen modules maken.
Terwijl je hier bent, bekijk enkele van onze andere berichten over de ontwikkeling van de React Native-app!