Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hybrid mobile applications for a fast development

Hybrid mobile applications for a fast development

Learn about the steps we followed on 8fit to have a mobile web-app solution for our platform with a real mobile experience.

Pedro Piñera Buendía

December 19, 2014
Tweet

More Decks by Pedro Piñera Buendía

Other Decks in Programming

Transcript

  1. Hybrid Mobile Applications for a fast development - 8fit @pepibumur

    @8fit_app “Any application that can be written in JavaScript, will eventually be written in JavaScript” Atwood's Law
  2. About me // Personal var name = "Pedro Piñera" var

    email = "pepi@8fit.com" // Professional var current_position = "Mobile Lead Dev at 8fit" var github = "github.com/pepibumur" var website = "www.ppinera.es" var experience = [ "Objective-C", "Swift", "Java"] var weak_experience = [ "Ruby", "Javascript"]
  3. 8fit Customized workout plans and healthy daily meals Cheaper than

    a trainer / Better than a gym For Android and iOS
  4. 8fit Customized workout plans and healthy daily meals Cheaper than

    a trainer / Better than a gym For Android and iOS Developed using Web technologies
  5. What did we need for 8fit? » Test the MVP

    ! " » Launch an initial version ASAP # » Be fast on the development/deployment $ » With limited resources % % %
  6. Knowledge » HTML ( & Jade ) » CSS (

    & Sass ) » JS ( & Coffee ) » Rails » Some about systems » No mobile knowledge
  7. Web Application (Javascript SPA) » They knew about web (and

    had enough knowledge to respect the mobile experience) » They had to develop only one application » They could launch updates on air (f*** reviews) » They just only needed a bit of mobile knowledge
  8. Index » Stack (web & mobile) » Building your communication

    bridge » Debugging » Pitfalls and recommendations » Results » Conclussions » ! :paella: !
  9. Advantages » Chunking: Fragments of HTML instead of a big

    page » Controllers: MVC or MVVM patterns instead of handling a complex DOM » Templates: Binding data to HTML templates » Routing: Custom navigation preserving web state » Local storage: capabilities of storing data on a browser for performance and offline access replace cookies and intensive data loads from web server
  10. Structure » Fonts » Images » Javascripts (Collections, Controllers, Helpers,

    Models, Routers, Lib, ...) » Sounds » Stylesheets » Templates (Jade files) » Translations
  11. Structure » Fonts » Images » Javascripts (Collections, Controllers, Helpers,

    Models, Routers, Lib, ...) -> application.js » Sounds » Stylesheets -> -> application.css » Templates (Jade files) -> templates.js » Translations -> -> translations.js
  12. Convert from Coffeescript to Javascript Convert from Sass to CSS

    Uglify and Minify Javascript Concatenate files
  13. Convert from Coffeescript to Javascript Convert from Sass to CSS

    Uglify and Minify Javascript Concatenate files ≈ 1000 plugins !
  14. How can we make 8fit mobile? Titanium Appcelerator Sencha Touch

    PhoneGap cd hello cordova platform add ios cordova plugin add org.apache.cordova.network-information cordova build ios cordova prepare ios cordova compile ios
  15. Not so hare-brained... » Build projects for Android/iOS » Build

    a communication layer » Add new controllers progressively » We had a mobile developer (to suffer from Apple certificates and Android Studio)
  16. 2. Add a webview that loads the URL Android webView.getSettings().setJavaScriptEnabled(true);

    webView.getSettings().setAppCacheEnabled(true); webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); webView.getSettings().setAllowFileAccess(true); Boolean remoteDebuggingSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; if(remoteDebuggingSupported) { webView.setWebContentsDebuggingEnabled(true); } clearCacheIfFirstRun(); webView.loadUrl("https://www.8fit.com/a/#");
  17. 2. Add a webview that loads the URL iOS -

    (UIWebView*)webView { if (!_webView) { _webView = [[UIWebView alloc] initForAutoLayout]; _webView.delegate = self; _webView.scrollView.scrollEnabled = NO; _webView.contentMode = UIViewContentModeScaleAspectFit; _webView.scalesPageToFit = YES; self.webView.delegate = self; NSURL *webURL = [NSURL URLWithString:WEB_APP_URL]; NSURLRequest *request = [NSURLRequest requestWithURL:webURL]; [_webView loadRequest:request]; } return _webView; }
  18. 3. Build and deploy » Upload the store assets !

    » Setup your Keystores/Release certificates " » Generate a new build and upload # » $ $ $
  19. Android // Communication Java -> Javascript webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new JavascriptInteractor(), "NativeBridge");

    class JavascriptInteractor { @JavascriptInterface public void buyIAPProduct(String productId) { // MyPaymentsController.buy... } } // Communication Java -> Javascript public void loadJS(String js) { webView.loadUrl("javascript:"+js); }
  20. Android » Asking for a payment NativeBridge.buyIAPProduct("pro_subscription_1mo"); » Reporting payment

    webview.loadJS("Ef.vent.trigger('payment:completed', "+payment.toString()+")")
  21. iOS UIWebViewDelegate + Custom URL Scheme - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest

    *)request navigationType:(UIWebViewNavigationType)navigationType { // eightfit://buyiapproduct?product_id=pro_subscription_1mo BOOL isNativeBridgeURL = [URLMatcher isForBridge:request.URL.absoluteURL]; if (isNativeBridgeURL){ [JLRoutes routeURL:request.URL.absoluteURL]; return NO; } return YES; }
  22. iOS UIWebViewDelegate + Custom URL Scheme github.com/joeldev/JLRoutes [JLRoutes addRoute:@"/buyiapproduct/:product_id" handler:^BOOL(NSDictionary

    *parameters) { NSString *productId = parameters[@"product_id"]; // defined in the route by specifying ":product_id" [PaymentsController buyProduct:product_id withCompletion:^void (NSError *error) { // Notify JS about the result }]; return YES; // return YES to say we have handled the route }];
  23. Some details » Bidirectional communication (question / response) » No

    way to expose Javascript to Mobile » Event handlers (JQuery, Backbone, ...)
  24. Some details » Bidirectional communication (question / response) » No

    way to expose Javascript to Mobile » Event handlers (JQuery, Backbone, ...) » No type validation
  25. User-Agent » Has the device support for Camera? » Does

    the app version support Payments? 8fit-iOS-8.1/iPhone-6/1.2.3 (iap, push, conn, res)
  26. Some examples of Controllers » Payments (IAP) » Video Player

    » Sound Player » Music Player » Push Notifications » Login with Facebook » Resources Downloader
  27. Dealing with two contexts » Native: » IDE Debugging Tools

    » Javascript -> Native » Chrome Inspector (Android) » Safari Web Inspector (iOS)
  28. What can I do? » Force calls to the bridge

    » Test if returned responses » Emulate the User-Agent » Everything on a real device
  29. 1) Native doesn't know about the JS Recommendation » Document

    the bridge: » Methods » Parameters » Parameters Types
  30. 2) Need a bit of Mobile Knowledge Recommendation » If

    you don't have a mobile developer: 1.Learn it, it's not very difficult Alternative: PhoneGap and some other Frameworks (plugins)
  31. 3) Experience close to mobile but not the same Recommendation

    » Move to native only the components/views where you want to have a trully mobile experience (e.g Interactive workouts)
  32. 4) Test the offline experience Recommendations » Show an alert

    if the first time the app is opened there's no internet connection » Pay attention on your frontend persistence
  33. 5) Be careful with the cache Recommendations » Clean it

    periodically » Force the renaming your files on every build
  34. First trainings are free Users pay $25 for 3 Months

    of PRO » Unlimited workouts » Meals plans » Personal Trainer support
  35. 6 Team members 2 years to live with cash in

    hand 230k forecast for 2015
  36. 6 Team members 2 years to live with cash in

    hand 230k forecast for 2015 1 million users by March 2016
  37. Conclussions » Javascript is not a bad solution for the

    beginning. » It might be restrictive in the future interactivity, animations, ...
  38. Conclussions » Javascript is not a bad solution for the

    beginning. » It might be restrictive in the future interactivity, animations, ... » Analyze your resources before starting a mobile solution. Try to have an expert on each field (with multidisciplinary skills)
  39. Conclussions » Javascript is not a bad solution for the

    beginning. » It might be restrictive in the future interactivity, animations, ... » Analyze your resources before starting a mobile solution. Try to have an expert on each field (with multidisciplinary skills) » Get ready for the battle with Javascript! We are getting amazing results
  40. WKWebView (iOS 8 Only) » Performance: Much faster! » More

    Javascript support // Evaluate Javascript - (void)evaluateJavaScript:(NSString *)js completionHandler:(void (^)(id, NSError *))handler; // Inject Javascript NSString *scriptSource = @"alert('WKWebView JS Call!')"; WKUserScript *userScript = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [wkWebView.configuration.userContentController addUserScript:userScript];