SlideShare uma empresa Scribd logo
1 de 100
Baixar para ler offline
Host your own
Over-the-air update service
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
Pillar Valley
Pillar Valley
Pillar Valley
My Awesome App
Standing on the shoulders
of giants
Pillar Valley
Buggy Valley
Buggy Valley
$
p = 0.5
$$
Nothingp = 0.5
Buggy Valley
p = 0.5
p = 0.5
Android Java Implementation
String redScreenPath = “file:///red-screen.js”;
String pillarValleyPath = “file:///pillar-valley.js”;
Android Java Implementation
String redScreenPath = “file:///red-screen.js”;
String pillarValleyPath = “file:///pillar-valley.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(pillarValleyPath);
}
Android Java Implementation
String redScreenPath = “file:///red-screen.js”;
String pillarValleyPath = “file:///pillar-valley.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(pillarValleyPath);**
}
** how does loadApp work?
Quick Recap
String redScreenPath = “file:///red-screen.js”;
String pillarValleyPath = “file:///pillar-valley.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(pillarValleyPath);**
}
** how does loadApp work?
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
Buggy Valley fits in perfectly with my use case.
Your MVP was just what I needed!
One small suggestion tho...
Original Buggy Valley
String redScreenPath = “file:///red-screen.js”;
String pillarValleyPath = “file:///pillar-valley.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(pillarValleyPath);
}
Modified Buggy Valley
String redScreenPath = “file:///red-screen.js”;
String aliceAppPath = “file:///alice-app.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(aliceAppPath);
}
Modified Buggy Valley
String redScreenPath = “file:///red-screen.js”;
String aliceAppPath = “file:///alice-app.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(redScreenPath);
} else {
loadApp(aliceAppPath);
}
Modified Buggy Valley
String newAliceAppPath
String aliceAppPath = “file:///alice-app.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(newAliceAppPath);
} else {
loadApp(aliceAppPath);
}
Modified Buggy Valley
String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”);
String aliceAppPath = “file:///alice-app.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(newAliceAppPath);
} else {
loadApp(aliceAppPath);
}
Modified Buggy Valley
String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”);
String aliceAppPath = “file:///alice-app.js”;
int randNum = getRandom();
if (isEven(randNum)){
loadApp(newAliceAppPath);
} else {
loadApp(aliceAppPath);
}
Glorified cURL
String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”);
String aliceAppPath = “file:///alice-app.js”;
if (newAliceAppPath != null){
loadApp(newAliceAppPath);
} else {
loadApp(aliceAppPath);
}
Wait but how does this benefit me?
JS Bundle
Native Modules
Currently on disk:
JS Bundle
Native Modules
Currently on disk:
Traditional update
New JS Bundle
New Native Modules
JS Bundle
Native Modules
Currently on disk:
Traditional update
New JS Bundle
New Native Modules
Avg binary size ~30Mb
JS Bundle
Native Modules
Currently on disk:
JS Bundle
Native Modules
Currently on disk:
Glorified cURL update
New JS Bundle
Native Modules
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
Glorified cURL fits in perfectly with my use case.
Your MVP was just what I needed!
It’s not very performant tho...
Glorified cURL
String newBobAppPath = cURLToDisk(“https://expo.io/@bob/app”);
String bobAppPath = “file:///bob-app.js”;
if (newBobAppPath != null){
loadApp(newBobAppPath);
} else {
loadApp(bobAppPath);
}
Glorified cURL
String newBobAppPath = cURLToDisk(“https://expo.io/@bob/app”);
String bobAppPath = “file:///bob-app.js”;
if (newBobAppPath != null){
loadApp(newBobAppPath);
} else {
loadApp(bobAppPath);
}
JS Bundle
We don’t want to load the JS bundle unnecessarily.
We only want to load the JS bundle if there’s a new change available.
Let’s take a step back
And think about how the web
works for a sec
The Web
<script src=“bundle.js” />
Big JS bundle
bundle.js
index.html
Taking a page out of the web book
{bundleUrl: ‘bundle.js’}
Big JS bundle
bundle.js
index.json
Taking a page out of the web book
{bundleUrl: ‘ios-1a2b3c.js’}
Big JS bundle
ios-1a2b3c.js
index.json
Bundle name is based off its md5 hash
Taking a page out of the web book
{bundleUrl: ‘ios-7a8b9c’}
Big JS bundle
ios-7a8b9c.js
index.json
Cache the bundleUrl
Only download bundleUrl
if we don’t have it cached
How do I use an OTA service in my app?
^ these are my app files
^ this is what my app looks like
How do I use an OTA service in my app?
dev tools GUI
^ push this button to upload app to expo server
How do I use an OTA service in my app?
Or use the cli if you prefer
> expo publish
Run this command in your project directory to upload to expo servers
How often is the server polled for updates?
The default behavior is to poll the server when the app starts up
What if I don’t like the default behavior?
You can use the Updates module to customize when you’d to update your app
^ from the docs page
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
I’m in a country where network latency
to your CDNs are really high
I’m in a country where network latency
to your CDNs are really high
How about hosting your own app then?
I’m in a country where network latency
to your CDNs are really high
How about hosting your own app then?*
* in our upcoming SDK release
How do I host my own app?
^ these are my app files
^ this is what my app looks like
> expo export
Run this command in your project directory
to dump your app to disk
How do I host my own app?
This is what gets dumped to disk
How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│   └── 1ecc2
└── bundles
      ├── android-01ee6.js
      └── ios-ee820.js
How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│   └── 1ecc2
└── bundles
      ├── android-01ee6.js
      └── ios-ee820.js
How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│   └── 1ecc2
└── bundles
      ├── android-01ee6.js
      └── ios-ee820.js
{bundleUrl: ‘ios-ee820.js’}
Big JS bundle
ios-ee820.js
ios-index.json
How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│   └── 1ecc2
└── bundles
      ├── android-01ee6.js
      └── ios-ee820.js
git push master
I pushed to GitHub because it has free static hosting.
You can host your app from any server.
How do I build my app binary?
> expo build:ios
Run this command in your project directory
How do I build my app binary?
> expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json
Run this command in your project directory
How do I build my app binary?
> expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json
{bundleUrl: ‘ios-ee820.js’}
Big JS bundle
ios-ee820.js
ios-index.json
^ This file is served first
Press this button
To download
How do I use this in development?
https://quinlanj.github.io/selfhost/ios-index.json
Convert to QR code
How do I use this in development?
Scan the QR code into the expo dev app
How do I use this in development?
http://localhost:8000/ios-index.json
Convert to QR code
How do I use this in development?
Scan the QR code into the expo dev app
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
This is what my app looks like.
I’ve installed it on my phone.
In development, let’s make a change by adding another pic
Push changes to GitHub
This is what my app looks like.
I’ve installed it on my phone.
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
Here is the server hosting my app
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
JS Bundle
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
New
JS Bundle
<Image source={require(‘cat.png’} />
<Image source={require(‘dog.png’} />
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is pulled down to filesystem?
New
JS Bundle
<Image source={require(‘cat.png’} />
<Image source={require(‘dog.png’} />
But how? It looks like these assets are fetched from filesystem
New
JS Bundle
<Image source={require(‘cat.png’} />
<Image source={require(‘dog.png’} />
We wrote a module to override asset resolution
New
JS Bundle
<Image source={require(‘cat.png’} />
<Image source={require(‘dog.png’} />
Module Logic:
Look for asset in the filesystem
If it’s not there, look for it from the server
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is pulled down to filesystem?
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is not on the filesystem
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
Let’s grab dog.png from server then!
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
Cached for future use
How come assets are stored by hash?
.
├── android-index.json
├── ios-index.json
├── assets
│   └── 1ecc2
└── bundles
      ├── android-01ee6.js
      └── ios-ee820.js
JS Bundle
<Image source={require(‘cat.png’)} />
We are requiring assets by their name, not by their hash
JS Bundle
require(‘cat.png’)
React native packager
{assetName: ‘cat.png’, hash:’1ecc2’}
App packaging
App.js
JS Bundle
<Image source={require(‘cat.png’} />
Module Logic:
Look for cat.png in the filesystem
If it’s not there, look for cat.png from the server
Recall
JS Bundle
Module Logic:
Look for 1ecc2 in the filesystem
If it’s not there, look for 1ecc2 from the server
Actual Implementation
{assetName: ‘cat.png’, hash:’1ecc2’}
How does this benefit me?
<Image source={require(‘cat1.png’} />
<Image source={require(‘crazy-cat.png’} />
<Image source={require(‘lime-cat.png’} />
…
This app displays the same cat picture
These cat pictures are all named something different
{assetName: ‘cat1.png’, hash:’1ecc2’}
{assetName: ‘crazy-cat.png’, hash:’1ecc2’}
{assetName: ‘lime-cat.png’, hash:’1ecc2’}
…
They all resolve to the same file on disk: 1ecc2
Roadmap
Buggy Valley App
Glorified cURLing App
Designing an OTA Service
Hosting Your Own Service
OTA Assets
Announcements
Announcements
We made a web application called Snack
Snack is like a JS Fiddle for react native apps
Snack is now open source, check it out at https://github.com/expo/snack-web

Mais conteúdo relacionado

Mais procurados

Mais procurados (20)

Autoscaling in Kubernetes
Autoscaling in KubernetesAutoscaling in Kubernetes
Autoscaling in Kubernetes
 
Kubernetes Deployment Strategies
Kubernetes Deployment StrategiesKubernetes Deployment Strategies
Kubernetes Deployment Strategies
 
Docker, LinuX Container
Docker, LinuX ContainerDocker, LinuX Container
Docker, LinuX Container
 
Getting started with Ansible
Getting started with AnsibleGetting started with Ansible
Getting started with Ansible
 
Kubernetes 101 - an Introduction to Containers, Kubernetes, and OpenShift
Kubernetes 101 - an Introduction to Containers, Kubernetes, and OpenShiftKubernetes 101 - an Introduction to Containers, Kubernetes, and OpenShift
Kubernetes 101 - an Introduction to Containers, Kubernetes, and OpenShift
 
Kubernetes Introduction
Kubernetes IntroductionKubernetes Introduction
Kubernetes Introduction
 
Introduction to GCP presentation
Introduction to GCP presentationIntroduction to GCP presentation
Introduction to GCP presentation
 
Terraform on Azure
Terraform on AzureTerraform on Azure
Terraform on Azure
 
Ansible
AnsibleAnsible
Ansible
 
(Draft) Kubernetes - A Comprehensive Overview
(Draft) Kubernetes - A Comprehensive Overview(Draft) Kubernetes - A Comprehensive Overview
(Draft) Kubernetes - A Comprehensive Overview
 
Terraform
TerraformTerraform
Terraform
 
Introduction to Ansible
Introduction to AnsibleIntroduction to Ansible
Introduction to Ansible
 
DevOps for database
DevOps for databaseDevOps for database
DevOps for database
 
Project calico - introduction
Project calico - introductionProject calico - introduction
Project calico - introduction
 
Ansible presentation
Ansible presentationAnsible presentation
Ansible presentation
 
Exploring Docker in CI/CD
Exploring Docker in CI/CDExploring Docker in CI/CD
Exploring Docker in CI/CD
 
Terraform
TerraformTerraform
Terraform
 
Ansible presentation
Ansible presentationAnsible presentation
Ansible presentation
 
Build automated Machine Images using Packer
Build automated Machine Images using PackerBuild automated Machine Images using Packer
Build automated Machine Images using Packer
 
Ansible - Hands on Training
Ansible - Hands on TrainingAnsible - Hands on Training
Ansible - Hands on Training
 

Semelhante a Hosting Your Own OTA Update Service

TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
Amazon Web Services
 
Appium mobile web+dev conference
Appium   mobile web+dev conferenceAppium   mobile web+dev conference
Appium mobile web+dev conference
Isaac Murchie
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
catherinewall
 
Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011
tobiascrawley
 

Semelhante a Hosting Your Own OTA Update Service (20)

Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
 
AWS CodeDeploy - basic intro
AWS CodeDeploy - basic introAWS CodeDeploy - basic intro
AWS CodeDeploy - basic intro
 
Обход проверки безопасности в магазинах мобильных приложений при помощи платф...
Обход проверки безопасности в магазинах мобильных приложений при помощи платф...Обход проверки безопасности в магазинах мобильных приложений при помощи платф...
Обход проверки безопасности в магазинах мобильных приложений при помощи платф...
 
Appium workship, Mobile Web+Dev Conference
Appium workship,  Mobile Web+Dev ConferenceAppium workship,  Mobile Web+Dev Conference
Appium workship, Mobile Web+Dev Conference
 
Appium mobile web+dev conference
Appium   mobile web+dev conferenceAppium   mobile web+dev conference
Appium mobile web+dev conference
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011Torquebox @ Raleigh.rb - April 2011
Torquebox @ Raleigh.rb - April 2011
 
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
 
Symfony Deployments on Heroku
Symfony Deployments on HerokuSymfony Deployments on Heroku
Symfony Deployments on Heroku
 
Node Summit 2018: Cloud Native Node.js
Node Summit 2018: Cloud Native Node.jsNode Summit 2018: Cloud Native Node.js
Node Summit 2018: Cloud Native Node.js
 
Silicon Valley Code Camp 2019 - Reaching the Cloud Native World
Silicon Valley Code Camp 2019 - Reaching the Cloud Native WorldSilicon Valley Code Camp 2019 - Reaching the Cloud Native World
Silicon Valley Code Camp 2019 - Reaching the Cloud Native World
 
Torquebox Asheville.rb April 2011
Torquebox Asheville.rb April 2011Torquebox Asheville.rb April 2011
Torquebox Asheville.rb April 2011
 
Running Microservices and Docker on AWS Elastic Beanstalk - August 2016 Month...
Running Microservices and Docker on AWS Elastic Beanstalk - August 2016 Month...Running Microservices and Docker on AWS Elastic Beanstalk - August 2016 Month...
Running Microservices and Docker on AWS Elastic Beanstalk - August 2016 Month...
 
Running Microservices on AWS Elastic Beanstalk
Running Microservices on AWS Elastic BeanstalkRunning Microservices on AWS Elastic Beanstalk
Running Microservices on AWS Elastic Beanstalk
 
Nodejs Intro - Part2 Introduction to Web Applications
Nodejs Intro - Part2 Introduction to Web ApplicationsNodejs Intro - Part2 Introduction to Web Applications
Nodejs Intro - Part2 Introduction to Web Applications
 
Can I Contain This?
Can I Contain This?Can I Contain This?
Can I Contain This?
 
Modern Web Application Development Workflow - EclipseCon France 2014
Modern Web Application Development Workflow - EclipseCon France 2014Modern Web Application Development Workflow - EclipseCon France 2014
Modern Web Application Development Workflow - EclipseCon France 2014
 

Último

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Último (20)

Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 

Hosting Your Own OTA Update Service

  • 1. Host your own Over-the-air update service
  • 2. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 7. Standing on the shoulders of giants
  • 10. Buggy Valley $ p = 0.5 $$ Nothingp = 0.5
  • 11. Buggy Valley p = 0.5 p = 0.5
  • 12. Android Java Implementation String redScreenPath = “file:///red-screen.js”; String pillarValleyPath = “file:///pillar-valley.js”;
  • 13. Android Java Implementation String redScreenPath = “file:///red-screen.js”; String pillarValleyPath = “file:///pillar-valley.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(pillarValleyPath); }
  • 14. Android Java Implementation String redScreenPath = “file:///red-screen.js”; String pillarValleyPath = “file:///pillar-valley.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(pillarValleyPath);** } ** how does loadApp work?
  • 15.
  • 16.
  • 17. Quick Recap String redScreenPath = “file:///red-screen.js”; String pillarValleyPath = “file:///pillar-valley.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(pillarValleyPath);** } ** how does loadApp work?
  • 18. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 19.
  • 20. Buggy Valley fits in perfectly with my use case. Your MVP was just what I needed!
  • 22. Original Buggy Valley String redScreenPath = “file:///red-screen.js”; String pillarValleyPath = “file:///pillar-valley.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(pillarValleyPath); }
  • 23. Modified Buggy Valley String redScreenPath = “file:///red-screen.js”; String aliceAppPath = “file:///alice-app.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(aliceAppPath); }
  • 24. Modified Buggy Valley String redScreenPath = “file:///red-screen.js”; String aliceAppPath = “file:///alice-app.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(redScreenPath); } else { loadApp(aliceAppPath); }
  • 25. Modified Buggy Valley String newAliceAppPath String aliceAppPath = “file:///alice-app.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(newAliceAppPath); } else { loadApp(aliceAppPath); }
  • 26. Modified Buggy Valley String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”); String aliceAppPath = “file:///alice-app.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(newAliceAppPath); } else { loadApp(aliceAppPath); }
  • 27. Modified Buggy Valley String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”); String aliceAppPath = “file:///alice-app.js”; int randNum = getRandom(); if (isEven(randNum)){ loadApp(newAliceAppPath); } else { loadApp(aliceAppPath); }
  • 28. Glorified cURL String newAliceAppPath = cURLToDisk(“https://expo.io/@alice/app”); String aliceAppPath = “file:///alice-app.js”; if (newAliceAppPath != null){ loadApp(newAliceAppPath); } else { loadApp(aliceAppPath); }
  • 29. Wait but how does this benefit me?
  • 31. JS Bundle Native Modules Currently on disk: Traditional update New JS Bundle New Native Modules
  • 32. JS Bundle Native Modules Currently on disk: Traditional update New JS Bundle New Native Modules Avg binary size ~30Mb
  • 34. JS Bundle Native Modules Currently on disk: Glorified cURL update New JS Bundle Native Modules
  • 35. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 36.
  • 37. Glorified cURL fits in perfectly with my use case. Your MVP was just what I needed!
  • 38. It’s not very performant tho...
  • 39. Glorified cURL String newBobAppPath = cURLToDisk(“https://expo.io/@bob/app”); String bobAppPath = “file:///bob-app.js”; if (newBobAppPath != null){ loadApp(newBobAppPath); } else { loadApp(bobAppPath); }
  • 40. Glorified cURL String newBobAppPath = cURLToDisk(“https://expo.io/@bob/app”); String bobAppPath = “file:///bob-app.js”; if (newBobAppPath != null){ loadApp(newBobAppPath); } else { loadApp(bobAppPath); } JS Bundle We don’t want to load the JS bundle unnecessarily. We only want to load the JS bundle if there’s a new change available.
  • 41. Let’s take a step back And think about how the web works for a sec
  • 42. The Web <script src=“bundle.js” /> Big JS bundle bundle.js index.html
  • 43. Taking a page out of the web book {bundleUrl: ‘bundle.js’} Big JS bundle bundle.js index.json
  • 44. Taking a page out of the web book {bundleUrl: ‘ios-1a2b3c.js’} Big JS bundle ios-1a2b3c.js index.json Bundle name is based off its md5 hash
  • 45. Taking a page out of the web book {bundleUrl: ‘ios-7a8b9c’} Big JS bundle ios-7a8b9c.js index.json Cache the bundleUrl Only download bundleUrl if we don’t have it cached
  • 46. How do I use an OTA service in my app? ^ these are my app files ^ this is what my app looks like
  • 47. How do I use an OTA service in my app? dev tools GUI ^ push this button to upload app to expo server
  • 48. How do I use an OTA service in my app? Or use the cli if you prefer > expo publish Run this command in your project directory to upload to expo servers
  • 49. How often is the server polled for updates? The default behavior is to poll the server when the app starts up
  • 50. What if I don’t like the default behavior? You can use the Updates module to customize when you’d to update your app ^ from the docs page
  • 51. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 52. I’m in a country where network latency to your CDNs are really high
  • 53. I’m in a country where network latency to your CDNs are really high How about hosting your own app then?
  • 54. I’m in a country where network latency to your CDNs are really high How about hosting your own app then?* * in our upcoming SDK release
  • 55. How do I host my own app? ^ these are my app files ^ this is what my app looks like
  • 56. > expo export Run this command in your project directory to dump your app to disk How do I host my own app?
  • 57. This is what gets dumped to disk How do I host my own app? . ├── android-index.json ├── ios-index.json ├── assets │   └── 1ecc2 └── bundles       ├── android-01ee6.js       └── ios-ee820.js
  • 58. How do I host my own app? . ├── android-index.json ├── ios-index.json ├── assets │   └── 1ecc2 └── bundles       ├── android-01ee6.js       └── ios-ee820.js
  • 59. How do I host my own app? . ├── android-index.json ├── ios-index.json ├── assets │   └── 1ecc2 └── bundles       ├── android-01ee6.js       └── ios-ee820.js {bundleUrl: ‘ios-ee820.js’} Big JS bundle ios-ee820.js ios-index.json
  • 60. How do I host my own app? . ├── android-index.json ├── ios-index.json ├── assets │   └── 1ecc2 └── bundles       ├── android-01ee6.js       └── ios-ee820.js git push master
  • 61. I pushed to GitHub because it has free static hosting. You can host your app from any server.
  • 62. How do I build my app binary? > expo build:ios Run this command in your project directory
  • 63. How do I build my app binary? > expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json Run this command in your project directory
  • 64. How do I build my app binary? > expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json {bundleUrl: ‘ios-ee820.js’} Big JS bundle ios-ee820.js ios-index.json ^ This file is served first
  • 66. How do I use this in development? https://quinlanj.github.io/selfhost/ios-index.json Convert to QR code
  • 67. How do I use this in development? Scan the QR code into the expo dev app
  • 68. How do I use this in development? http://localhost:8000/ios-index.json Convert to QR code
  • 69. How do I use this in development? Scan the QR code into the expo dev app
  • 70. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 71. This is what my app looks like. I’ve installed it on my phone.
  • 72. In development, let’s make a change by adding another pic
  • 73. Push changes to GitHub
  • 74. This is what my app looks like. I’ve installed it on my phone.
  • 75. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: JS Bundle
  • 76. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: JS Bundle quinlanj.github.io Here is the server hosting my app
  • 77. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: JS Bundle quinlanj.github.io An update is ready!
  • 78. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: JS Bundle quinlanj.github.io An update is ready! Files to be served: New JS Bundle
  • 79. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: JS Bundle quinlanj.github.io An update is ready! Files to be served: New JS Bundle JS Bundle
  • 80. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle
  • 81. New JS Bundle <Image source={require(‘cat.png’} /> <Image source={require(‘dog.png’} />
  • 82. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle ? dog.png is pulled down to filesystem?
  • 83. New JS Bundle <Image source={require(‘cat.png’} /> <Image source={require(‘dog.png’} /> But how? It looks like these assets are fetched from filesystem
  • 84. New JS Bundle <Image source={require(‘cat.png’} /> <Image source={require(‘dog.png’} /> We wrote a module to override asset resolution
  • 85. New JS Bundle <Image source={require(‘cat.png’} /> <Image source={require(‘dog.png’} /> Module Logic: Look for asset in the filesystem If it’s not there, look for it from the server
  • 86. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle ? dog.png is pulled down to filesystem?
  • 87. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle ? dog.png is not on the filesystem
  • 88. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle ? Let’s grab dog.png from server then!
  • 89. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle
  • 90. This is what my app looks like. I’ve installed it on my phone. Currently on filesystem: quinlanj.github.io An update is ready! Files to be served: New JS Bundle Cached for future use
  • 91. How come assets are stored by hash? . ├── android-index.json ├── ios-index.json ├── assets │   └── 1ecc2 └── bundles       ├── android-01ee6.js       └── ios-ee820.js
  • 92. JS Bundle <Image source={require(‘cat.png’)} /> We are requiring assets by their name, not by their hash
  • 93. JS Bundle require(‘cat.png’) React native packager {assetName: ‘cat.png’, hash:’1ecc2’} App packaging App.js
  • 94. JS Bundle <Image source={require(‘cat.png’} /> Module Logic: Look for cat.png in the filesystem If it’s not there, look for cat.png from the server Recall
  • 95. JS Bundle Module Logic: Look for 1ecc2 in the filesystem If it’s not there, look for 1ecc2 from the server Actual Implementation {assetName: ‘cat.png’, hash:’1ecc2’}
  • 96. How does this benefit me?
  • 97. <Image source={require(‘cat1.png’} /> <Image source={require(‘crazy-cat.png’} /> <Image source={require(‘lime-cat.png’} /> … This app displays the same cat picture These cat pictures are all named something different
  • 98. {assetName: ‘cat1.png’, hash:’1ecc2’} {assetName: ‘crazy-cat.png’, hash:’1ecc2’} {assetName: ‘lime-cat.png’, hash:’1ecc2’} … They all resolve to the same file on disk: 1ecc2
  • 99. Roadmap Buggy Valley App Glorified cURLing App Designing an OTA Service Hosting Your Own Service OTA Assets Announcements
  • 100. Announcements We made a web application called Snack Snack is like a JS Fiddle for react native apps Snack is now open source, check it out at https://github.com/expo/snack-web