App mòbil amb React Native: arbres singulars de Barcelona
Contingut
- 1 Introducció
- 2 MapView i react-native-maps (Google Maps)
- 3 Projecte react-native-open-street-map (sense Google Maps). Primavera 2020
- 4 Mapes sense Google Maps i amb Expo (solució final). Primavera 2020
- 5 Desenvolupament
- 6 Publicar a la Google Store
- 7 React-Native i mapes (primavera 2022)
- 8 Reduir el tamany de l'app generada per Expo
Introducció
Es tracta de fer una app Android, com a procés d'aprenentatge de React Native per fer aplicacions natives. La idea és acabar tot el cicle del projecte fins a publicar l'app al Google Play Store.
L'app consta de dues pantalles:
- la primera és un llistat dels arbres, on s'indica la distància dels arbres fins la nostra posició actual. Quan cliquem sobre un arbre es posa de color verd, que significa que l'hem visitat.
- La segona pantalla ha de ser el mapa fet amb Openlayers/Leaflet. Però aquesta part de posar mapes amb Reactnative encara no ho tinc controlat. (mirar [1])
L'aplicació és una gamificació dels Arbres Singulars de Barcelona. Es tracta d'anar col·leccionant aquests arbres. Els arbres descoberts surten en verd, i t'indica el % dels arbres descoberts. Per tant, és un joc per passejar amb família mentre es van coneixent els arbres singulars i es coneixen nous barris de la ciutat. I si es vol anar ràpid o corrents, col·leccionar aquests arbres també és un alicient a la pràctica esportiva.
Github
MapView i react-native-maps (Google Maps)
Hi ha projectes per adaptrar el mòdul react-native-maps a OSM, però això ho faré més avall. De moment em conformo en fer funcionar el projecte amb Google Maps.
Documentació de expo, que és el sistema que estic fent servir per desenvolupar aplicacions reactivenative.
$ expo install react-native-maps $ npm install react-native-maps --save-exact
Configuration
Apartat: Deploying to a standalone app on Android
Apartat: If you already have not configured Google Sign In
1. Android package name: el que he posat en el app.json. En aquest cas: "package": "org.joanillo.ArbresBarcelona",
2. Open your browser to the Google API Manager and create a project.
Actualizar la cuenta
Estás a un paso de desbloquear Google Cloud Platform íntegramente.
No se te aplicará ningún cargo hasta que tus créditos gratuitos se agoten o caduquen (lo que suceda primero).Más información
Projecte: ArbresBarcelona
3. Once it's created, go to the project and enable the Google Maps SDK for Android
- Go back to https://console.developers.google.com/apis/credentials and click Create Credentials, then API Key.
API_KEY: ************************
4. Go back to https://console.developers.google.com/apis/credentials and click Create Credentials, then API Key.
5. In the modal that popped up, click RESTRICT KEY.
6. Choose the Android apps radio button under Key restriction.
7. Click the + Add package name and fingerprint button.
De moment aquesta informació no la necessito:
¿Cómo restrinjo mi clave de API a aplicaciones de Android concretas? Si quieres restringir una clave de API a determinadas aplicaciones de Android, proporciona una huella digital de certificado de depuración o de publicación. Huella digital de certificado de depuración Linux o macOS: $ keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android Huella digital de certificado de publicación $ keytool -list -v -keystore your_keystore_name -alias your_alias_name Sustituye your_keystore_name por la ruta completa y el nombre del almacén de claves, incluida la extensión .keystore. Sustituye your_alias_name por el alias que asignaste al certificado cuando lo creaste.
Restringir el uso a tus aplicaciones de Android Añade el nombre del paquete y la huella digital del certificado de firma SHA‑1 para restringir el uso a tus aplicaciones para Android
8. Add your android.package from app.json (eg: ca.brentvatne.growlerprowler) to the Package name field.
En el nostre cas: org.joanillo.ArbresBarcelona
Huella digital del certificado SHA-1: he de posar la que em diu el punt 9
9. run expo fetch:android:hashes
$ expo fetch:android:hashes Configuring credentials for joanillo_reactnative in project geo-example Google Certificate Fingerprint: *************** Google Certificate Hash (SHA-1): *************** Google Certificate Hash (SHA-256): *************** Facebook Key Hash: ***************
Note: if you are using Google Play signing (no és el meu cas), this app will be signed with a different key after publishing to the store, and you'll need to use the hashes displayed in the Google Play console.
10. Copy Google Certificate Fingerprint from the output from step 9 and insert it in the "SHA-1 certificate fingerprint" field.
11. Copy the API key (the first text input on the page) into app.json under the android.config.googleMaps.apiKey field. See an example diff.
"android": { "package": "org.joanillo.ArbresBarcelona", "config": { "googleMaps": { "apiKey": "**************************" } } }
12. Press Save and then rebuild the app like in step 1.
Exemples
i ara ja puc provar els exemples de:
Concretament puc anar directament a la carpeta example/examples/, i provar els diferents exemples. La única cosa que he de fer és copiar el codi de l'exemple en el meu App.js del projecte. He provat els següents exemples:
- https://github.com/react-native-community/react-native-maps/blob/master/example/examples/DefaultMarkers.js
- EventListener.js
- FitToSuppliedMarkers.js -> aquest codi m'interessa. Donat un conjunt de markers, posicionar-los en el mapa de manera que hi càpiguen tots.
- MarkerTypes.js -> interessa com a exemple de onPress sobre el Marker
- MassiveCustomMarkers.js
- MyLocationMapMarker.js ?
- OnPoiClick.js
- TestIdMarkers.js
- ViewsAsMarkers.js
Projecte react-native-open-street-map (sense Google Maps). Primavera 2020
És un fork de react-native-maps amb la idea d'utilitzar els mapes de OSM amb el component MapView.
al fitxer package.json posem a dependències:
"react-native-open-street-map": "https://github.com/enieber/react-native-open-street-map.git"
de manera que quan fem
$ npm install
s'instal·la aquesta dependència. Un cop instal·lat podem veure dins de node_modules/ la carpeta react-native-open-street-map, que significa que el mòdul ja està instal·lat.
Prove el parell de codis d'exemple que es donen. Ara bé, dóna problemes:
requireNativeComponent: OpenAirMap was not found in the UIManager $ expo --version $ expo-cli --version 3.20.1
i informant-nos una mica veiem que aquesta solució seria vàlida per al Android Studio i la manera com té de fer el build de l'aplicació (gradle), però jo estic utilitzant Expo que és una manera no-nativa, és una porta fàcil d'entrada al desenvolupament react-native, però té les seves limitacions.
Having React Native Maps is a huge plus in Expo. It would be great to have Open Street Maps integrated too in order to have a choice to Google Maps. Veure el que es comenta en el següents fils:
- https://expo.canny.io/feature-requests/p/open-street-maps-integration
- https://expo.canny.io/feature-requests/p/add-mapbox-gl-support
- https://stackoverflow.com/questions/53144067/creating-an-osm-map-app-with-react-native-and-expo
De moment (abril 2020) no hi ha suport de Expo als react-native-maps'. La informació que he trobat de react-native-open-street-map no és per expo, sinó per l'Android Studio directament (gradle).
Però això hauria de canviar en el futur, doncs hi ha interès per no dependre de Google Maps. Però la plataforma Expo s'hi han de posar en el tema. Com es comenta en el fil, aquí hi ha una solució que exploro en el següent apartat:
Mapes sense Google Maps i amb Expo (solució final). Primavera 2020
És una solució feta a mida que no depèn de MapView.
$ git clone https://github.com/wende60/hiker.git $ cd hiker $ npm install $ npm start
Right now I am using the tiles from:
An API key is needed and has to be added in settings/mapConfig.js. For small tile usage you can get it for free.
Servidor de tiles:
- https://tile.thunderforest.com/
- Hobby Project: Free (Tile requests per month 150,000)
Ja m'havia registrat anteriorment, i la API Key era: f695b42************
Ara bé, el projecte d'entrada no se m'instal·la perquè, encara que és recent (octubre 2019), les versions de expo-cli del desenvolupador devien estar una mica desfasades.
Quan compilo el projecte amb expo:
32.0.0 is not a valid SDK version $ expo --version $ expo-cli --version 3.20.1 $ expo diagnostics Expo CLI 3.20.1 environment info: System: OS: Linux 4.15 Linux Mint 19.2 (Tina) Shell: 4.4.20 - /bin/bash Binaries: Node: 12.16.1 - ~/.nvm/versions/node/v12.16.1/bin/node npm: 6.13.4 - ~/.nvm/versions/node/v12.16.1/bin/npm npmPackages: expo: ^32.0.0 => 32.0.6 react: 16.5.0 => 16.5.0 react-native: https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz => 0.57.1 npmGlobalPackages: expo-cli: 3.20.1
Torno a reinstal·lar el expo-cli---
npm -g uninstall expo-cli npm install --global expo-cli
però s'ha quedat tot amb les mateixes versions.
En el package.json tinc: "dependencies": { "expo": "^32.0.0", "dependencies": { "expo": "^32.0.0", "react": "16.5.0", "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz" "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz" que és la versió que tinc en d'altres projectes i en el app.json poso: "sdkVersion": "32.0.0", torno a fer npm install Your project is in SDK version >= 33.0.0, but the expo package version seems to be older. i tot i aquest missatge a la consola, avança en la instal·lació, però encara no funciona. Ara diu: Unable to resolve "react-native/Libraries/Components/View/ViewStylePropTypes" from "node_modules/react-native-reanimated/src/createAnimatedComponent.js" Failed building JavaScript bundle. "react": "~16.9.0",
Solució: en comptes de fer un git clone, començar un projecte des de zero, i copiar els fitxers:
$ expo init hiker2
és un codi desactualitzat i he hagut de fer uns quants canvis: rutes relatives dels fitxers i maneres de fer imports als mòduls que són d'una versió més antiga.
I finalment ja funciona. Almenys ja tinc un codi que funciona amb react-native i expo, i que no depèn de Google Maps.
Depèn dels tiles de thunderforest.com (no confondre amb OSM, OSM de fet no és un servidor de Tiles) i té la restricció de 150000 peticions/mes.
És un bon punt de partida per començar a pintar els meus arbres sobre un mapa.
Desenvolupament
Solucionat el tema de com programar un mapa que no depengui de Google Maps, en el projecte (que de fet és un procés d'aprenentatge perquè no tenia experiència amb React) he hagut de resoldre aquestes qüestions.
1. componentDidMount() i render(). S'ha de vigilar, i és motiu d'errors. El primer render() es fa abans del componentDidMount(), que és on faig el setState del contingut del fitxer JSON. componentWillMount() funciona, però està deprecated, no s'ha de fer servir. S'ha de tenir molt clar el cicle de vida de l'aplicació, i què es pot fer o no es pot fer en el render(). Concretament, dins el render() no podem canviar l'estat de cap variable.
2. event onStartShouldSetResponder: Tinc el problema de clicar sobre la icona de l'arbre per canviar de vermell a verd. Però no funciona el onPress sobre el component Image (ni sobre View). El onPress està pensat per als Touchables. Però si encapsulo la Image sobre un TouchableOpacity tampoc funciona (a més gent li passa, és una mica tricky). Per sort existeix l'event onStartShouldSetResponder que resol bé el meu problema.
3. Persistència de les dades: AsyncStorage: el component AsyncStorage em permet guardar els settings d'una aplicació. Concretament a mi m'interessa guardar un array dels arbres que ja s'han visitat (pintats de color verd), i aquesta informació s'ha de guardar entre ús i ús de l'aplicació, i també s'ha de carregar al principi. Com es comenta a [2], per llegir/escriure fitxers hi ha el mòdul react-native-fs, però si el que es vol es guardar els settings d'una aplicació amb persistència, amb AsyncStorage n'hi ha prou.
4. How to update a component’s prop:
Tinc el component Grid, on es visualitza el % d'arbres verds, i per això he creat la variable d'estat discoveredPercent. En el Grid es visualitza la capa de Tree, i per tant li passo com a prop aquest valor. Ara bé, és en el component Tree on descubreixo nous arbres, i aquí és on es fa la modificació del valor del percentatge. Per tant, hauria de fer una modificació del props.discoveredPercent i que se n'enteri el Grid, però això a ReactJS no es pot fer.
Whether you declare a component as a function or a class, it must never modify its own props. React is pretty flexible but it has a single strict rule: All React components must act like pure functions with respect to their props
Però en aquest enllaç hi ha una pista de com això es pot aconseguir.
Ha funcionat bé, però com es comenta en l'enllaç, aquesta manera de fer no és molt ortodoxa. Els canvis que s'han fet són:
a Grid.js
en el constructor (important): this.onDiscoveredPercentChange = this.onDiscoveredPercentChange.bind(this); en el render(): <Trees gridData={this.state.gridData} location={this.props.location} zoom={this.props.zoom} discoveredPercent={this.state.discoveredPercent} onDiscoveredPercentChange={this.onDiscoveredPercentChange} /> dins del component, definim la funció: onDiscoveredPercentChange(newValue) { this.setState({ discoveredPercent: newValue }); //console.log(newValue) }
A Tree.js, en un parell de llocs he de posar:
this.props.onDiscoveredPercentChange(percent.toFixed(2))
i d'aquesta manera el component Grid se n'entera del canvi de percentatge que he fet en el component Tree.
Versions
La versió 1.0 és sense mapes, només el FlatList amb el llistat de tots els arbres. Es pot activar el posicionament, i per tant sé quina és la direcció des de la meva posició actual fins a l'arbre. A més a més he calculat el heading, que és la direcció a la que em moc. I per tant, amb aquestes dues dades, ja puc saber en quina direcció m'he de moure/desviar, i això ho mostro amb unes brúixoles.
Tot això funciona, sembla ser que la FlatList està una mica carregada d'informació, i en fase de desenvolupament amb Expo no és molt fluïd i surt el missatge:
VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc. Object {
Ara bé, amb el APK va bé, fluid. S'ha de mirar a veure si es pot millorar.
Tot el desenvolupament l'he fet a la carpeta geo-example/, però ara ja he migrat a ArbresBarcelona/.
D'altra banda, he estat desenvolupant a la carpeta thunderforest/ la versió del mapa (finalment mapes sense google Maps, una solució nativa on no cal instal·lar cap llibreria). I ja funciona, i en la versió 2.0 hauré d'integrar la v1.0 amb aquesta funcionalitat (es podrà intercanviar entre les dues pantalles, el llistat i el mapa).
Publicar a la Google Store
- https://themanifest.com/mobile-apps/how-publish-app-google-play-step-step-guide
- https://reactnative.dev/docs/signed-apk-android
Step 1: Create a Developer Account
Nom del desenvolupador: joanillo joanqc@gmail.com www.joanillo.org +34-636517785 identificador del compte de desenvolupador: *******************
Step 2: Plan to Sell? Link Your Merchant Account De moment res.
Step 3: Create an App
- idioma: català - ca
- títol: Arbres Singulars de Barcelona
- descripció breu: Visita i col·leccionar tots els arbres monumentals de Barcelona
- descripció completa: Llistat de tots els arbres catalogats de Barcelona. Es mostra distància i direcció per arribar finns l'arbre, i pots marcar els arbres visitats. A veure si pots completar tota la col·lecció. Són 146 arbres distribuïts per tots els barris.
Ara falta acabar d'omplir tota la fitxa, crear la icona, captures de pantalla, etiquetes i més coses.
També enllaç a una política de privacitat, dir que l'aplicació és gratuïta, posar una categoria i etiquetes, i bastantes coses més. Després s'ha de pujar el APK que s'ha generat des de Expo. I un cop fet tot, ha de sortir el missatge llest per publicar. Amb aquest missatge no s'ha acabat, he d'aconseguir que surti el missage pendent de publicació. I aleshores esperar (degut al COVID-19, sembla ser que pot trigar una setmana).
Una de les coses que li passa al meu APK i que detecta el Google Store és que és massa gran (pesat). Això ja en sóc conscient, i ve de que s'ha desenvolupat amb el Expo. En el següent apartat es comenta de com es pot reduir el tamany.
React-Native i mapes (primavera 2022)
Resum
Després de dos anys, reprenem el projecte i miro si hi ha hagut algun progrés amb la possibilitat d'utiltizar la llibreria openlayers a react-native. La conclusió és que no especialment. Si vull utilitzar Expo, puc utilitzar react-native-maps amb Google Maps. Si vull utilitzar els mapes de OSM la única possibilitat és utilitzar el projecte hiker i modificar-lo (tal com s'explica). hiker ja m'havia funcionat el 2020, i ara el 2022 també em funciona i he aconseguit posar els mapes de OSM i de thunderforest.
Aquí va un resum de les proves que he fet, del que ha funcionat i del que no. Cal dir que hi ha coses que no han funcionat perquè són projectes pensats per a Android Studio i Gradle, i jo de moment vull continuar amb Expo com a entorn de desenvolupament. Si instal·lo i utilitzo Android Studio podria fer funcionar alguns dels projectes que es comenten.
A. react-native-maps
- https://github.com/react-native-maps/react-native-maps -> utilitza els mapes de Google Maps (es necessita una key)
conclusió: funciona amb Expo i Google Maps. No he aconseguit fer funcionar els mapes de OSM.
Però sí que hi ha una possibilitat d'utilitzar aquest enllaç, com s'explica a:
You can use a custom Tile Overlay (OpenStreetMap too) in react-native-maps package: https://github.com/react-native-maps/react-native-maps
(scroll to Using a custom Tile Overlay section)
You need to add api key. You don't need to use Maps API at all and the key won't be used in that case.
Mans a l'obra:
Primer de tot creo una API key de Google Maps, doncs la necessitaré, encara que no es faria servir si vull els mapes de OSM:
key=API_KEY AIzaSyDNocxQJ6Dt9CnT001Zfrk0qVF1pUa2kiw
El problema està en què aquest projecte està pensat per a Android Studio. Per exemple, la API_KEY està dins del Manifest.xml.
I react-native-maps amb Expo? Sí que és possible:
Dins del package.json puc posar la API KEY:
"android": { "config": { "googleMaps": { "apiKey": "AIzaSyDNocxQJ6Dt9CnT001Zfrk0qVF1pUa2kiw" } } }
Creo el projecte:
$ expo init react-native-maps-exemple $ expo install react-native-maps
copio a Apps.js el codi que se'ns proposa a l'enllaç, i fem npm start i ja està, ja tenim un mapa (de moment amb Google Maps)
$ npm start
El MapView bàsic de l'exemple, que representa un mapa de tot el món:
<MapView style={styles.map} />
I ara ja puc fer coses més interessants:
<MapView initialRegion={{ latitude: 37.78825, longitude: -122.4324, latitudeDelta: 0.0922, longitudeDelta: 0.0421, }} style={styles.map} />
Per tant, funciona bé amb Google Maps, i a partir d'aquí no hauria de ser difícil crear els markers i fer coses més interessants, com es mostra a la documentació.
I ara puc fer una cosa que no queda gens clara, en el MapView puc posar:
mapType={Platform.OS == "android" ? "none" : "standard"}
i efectivament em desapareix el mapa de Google Maps (ja no es renderitza), però no queda clar com s'ha de fer per renderitzar els mapes de OSM.
La solució vindria per react-native-maps-osmdroid, que és un clon de react-native-maps pensat per a OSM. Però és Android Studio
Si vull fer servir Google Maps aquesta sí que és una solució, que a partir de l'exemple bàsic el puc fer créixer i fer el mapa amb les meves necessitats.
B. Leaflet (per explorar)
Una possibilitat és utilitzar Leaflet:
C. (per explorar)
Anem a provar:
$ expo init react-native-map-exemple
No l'he pogut fer funcionar, no recordo per què.
D.react-native-open-street-map (no ha funcionat, Android Studio)
Una altra prova:
Hauria de fer primer crear un nou projecte i també fer el git clone, i barrejar-ho, doncs m'interessa el codi del clone, però jo desenvolupo amb expo i necessito l'esquelet del Expo.
$ expo init react-native-open-street-map-prova
$ git clone https://github.com/Multiware-Tecnologia/react-native-open-street-map $ cd react-native-open-street-map/ $ npm install -g expo-cli (cal si ja ho havia fet? crec que no...)
Instal·lo totes les dependències
$ npm install
No funciona...
E. react-native-maps-osmdroid
El problema està en què també està pensat per a Andoid Studio. A veure si funciona...
$ expo init react-native-maps-osmdroid-exemple $ cd react-native-maps-osmdroid-exemple $ expo install react-native-maps $ expo install react-native-maps-osmdroid
copio a Apps.js el codi que se'ns proposa a l'enllaç, i fem npm start i ja està, ja tenim un mapa (de moment amb Google Maps), igual que funcionava el react-native-maps. Però no funciona amb OSM
$ npm start
F. Mapbox, per explorar
Es recomana aquest enllaç, i s'hauria d'explorar
A mi en principi Mapbox no m'interessa, però per aquesta via tindria els tiles de OSM.
G. hiker: hiker4 i seg (funciona)
NOTA: funcionava el 2020, però ara el 2022 he començat de 0 i no havia repassat massa què havia fet en el passat. Com que el 2020 havia fet hiker/ i hiker2/, la prova per on començo el 2020 serà hiker3/ i següents.
NOTA: si no m'hagués funcionat el servidor de tiles de OSM, una possibilitat era utilitzar la descàrregar de tiles i així poder treballar offline, però aquesta opció no interessa. Per exemple, per descarregar tiles es pot utilitzar el Mobile Atlas Creator, que ja havia utilitzat en el seu dia. L'aplicació de mòbil OsmAnd, que utilitzo, també fa la descàrrega de tiles.
mirar aquest projecte que hauria de funcionar i està fet amb Expo:
git clone https://github.com/wende60/hiker cd hiker npm install npm start
la clau de thunderforest ja la tenia: f695b42354e84626afef4de11a5d6080. S'ha de posar a settings/mapConfig.js
i aquí veig com també hi ha la possibilitat d'utilitzar OSM.
A partir d'aquí dóna una sèrie d'errors que vaig solucionant sobre la marxa:
this project uses SDK 32.0.0, but this version of Expo Go only supports the following SDKs: 44.0.0, 43, 42, 41...
solució: creo de nou un projecte buit amb la meva versió d'Expo, i copio els fitxers.
Com que va ser una versió anterior, hi ha alguna cosa que s'ha d'arreglar. Per exemple, ruta relativa dels fitxers
TypeError: undefined is not an object (evaluating '_expo.Constants
solució:
npm i --save expo-constants import Constants from 'expo-constants';
[Unhandled promise rejection: ReferenceError: Can't find variable: Permissions
això dels Permissions ja ho havia solucionat a ArbresBarcelonaRN amb la pausa de 2 anys 2020-22, és un problema d'una versió anterior de react natove.
$ npm install expo-location
Més errors:
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_expo.FileSystem.getInfoAsync')]
I work with "sdkVersion": "35.0.0". It seems that Expo changed its API. Now you need to install a separate dependency:
npm i --save expo-file-system And then to import FileSystem object independently for your component: import * as FileSystem from 'expo-file-system';
Més errors:
Animated.event now requires a second argument for options at node_modules/react-native/Libraries/Animated/AnimatedEvent.js:141:6 in constructor at node_modules/react-na ... at src/components/Grid.js:45:32 in constructor
Per solucionar-ho és molt senzill:
a Grid.js s'ha d'afegir un segon argument i la cosa queda:
onPanResponderMove: Animated.event([ null, { dx: this.state.pan.x, dy: this.state.pan.y }, ],{useNativeDriver: false}),
i ara ja funciona tot sense cap mena d'error, excepte que no es carreguen els tiles.
I d'altra banda, amb aquest sistema no sé ben bé com posaré uns markers (s'han de poder posar doncs es visualitza una creu i una rodoneta, que seran uns makers).
A partir d'aquí el meu problema serà poder pintar els tiles, ja siguin de thunderforest o de OSM. I per entendre el procés s'ha de tenir clar que els tiles es descarreguen d'un servidor de tiles (comprovar que la ruta és correcte), i que es guarden com a fitxers .png en el dispositiu (i que funciona com a cache sempre que cal).
Miro la ruta on es guarden els fitxers en el Android i penso que aquí pot haver-hi un problema.
file:///data/user/0/host.exp.exponent/files/ExperienceData/%2540joanillo_reactnative%252Fhiker2/outdoors/tiles/14/8290/6118.png
- https://forums.expo.dev/t/error-invalid-filesystem-uri/3546/4
- https://github.com/expo/expo/issues/2701
- https://mothereff.in/utf-8
- https://github.com/MostWantIT/react-native-video-editor/issues/6
Mirant la ruta del fitxer on es guarden els png penso que podia haver un problema de doble codificació (però al final no...)
%2540 -> %40 que és el \x40, equivalent a l'@ %252F -> %2F que és el \x2F, equivalent a /
Vaig estar mirant de reemplaçar els caràcters i fent proves, però no tenia res a veure. La solució va venir per una altra banda:
Val, ja està, ja funciona hiker2 (maig 2022), amb thunderforest i la API KEY
La línia ha quedat de la següent manera:
this.mounted && this.setState({ tileSource: { uri: fileData.uri }}); //el format d'aquesta línia és diferent en el codi original
El problema és ara els tiles de OSM, que no funcionen.
funciona: $ wget https://tile.thunderforest.com/outdoors/13/4130/3060.png?apikey=f695b42354e84626afef4de11a5d6080 no funciona: (però sí que es veu en el navegador) $ wget https://b.tile.openstreetmap.org/13/4130/3060.png --2022-05-02 10:48:38-- https://b.tile.openstreetmap.org/13/4130/3060.png S'està resolent b.tile.openstreetmap.org (b.tile.openstreetmap.org)… 151.101.134.137, 2a04:4e42:1f::649 S'està connectant a b.tile.openstreetmap.org (b.tile.openstreetmap.org)|151.101.134.137|:443… conectat. HTTP: s'ha enviat la petició, s'està esperant una resposta… 403 Forbidden 2022-05-02 10:48:38 ERROR: 403 Forbidden. però així sí que funciona: $ curl --output fitxer.png https://a.tile.openstreetmap.org/13/4130/3060.png
Per tant el problema és de permisos per accedir als servidors de tiles de OSM.
els tiles d'OSM no em funcionen des de react-native, i des del chrome del portàtil sí, perquè una de les condicions és que:
- Valid HTTP User-Agent identifying application. Faking another app’s User-Agent WILL get you blocked.
- If known, a valid HTTP Referer.
- DO NOT send no-cache headers. (“Cache-Control: no-cache”, “Pragma: no-cache” etc.)
- Cache Tile downloads locally according to HTTP Expiry Header, alternatively a minimum of 7 days.
- Maximum of 2 download threads. (Unmodified web browsers’ download thread limits are acceptable.)
- https://stackoverflow.com/questions/60942699/expo-file-system-firebase-storage-cant-retrieve-file-403-error
- https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome
Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Mobile Safari/537.36 User-Agent: <product> / <product-version> <comment> User-Agent: Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Mobile Safari/537.36
Per tant el que he de fer és posar una capçalera adequada en la meva petició, i simular que estic fent la petició al servidor des d'un navegador reconegut (el user-agent).
Ho he aconseguit!, he aconseguit posar els tiles de OSM. En el fileSystemHelper.js hem d'afegir els headers. La cosa queda:
await FileSystem.downloadAsync( source, FileSystem.documentDirectory + file, { headers: { 'Content-Type': 'image/png', 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Mobile Safari/537.36' } } );
Recordar que la cache funciona, i per tant els nous tiles no es veuen. He d'esborrar la cache i els fitxers per tal de què es tornin a descarregar. En el Android fem:
- Configuració > Aplicacions > Gestiona les aplicacions > Expo Go > Esborra les dades (totes o només la cache?)
I ja està, ja tenim funcionant el projecte hiker (aquesta versió li diem hiker4, i a partir d'aquí ja puc anar al hiker5 per tal d'afegir tots els markers dels arbres. Quan ja tingui afegits tots els arbres, ja ho podré integrar amb la resta de l'aplicació (que mentrestant ja sé com es fa el canvi de pantalles entre dos tabs).
Reduir el tamany de l'app generada per Expo
(TBD)
creat per Joan Quintana Compte, maig 2020, maig 2022