Programming

ReactJS Server Side Rendering : Calling Web Services (APIs) From Server Side

A step by step guide to support server side rendering in reactjs : Calling Web Services (APIs) From Server Side

Before learning how to implement server side rendering in reactjs , let us know why server side rendering ?

Why Server Side Rendering ?

  1. Performance gain for initial page load : Server side rendering improves the performance of initial page load, this is because it reduces number of calls from client to server. Rather than loading empty page first, then call api , get the response then iterate the response to create ui components at client side, for server side rendering, many client-server calls will be removed and for the first render itself the client will get complete HTML with all the data filled. So the browser will just render quickly the final HTML. See the below image taken from Udemy tutorial on ReactJS, which gives complete flow diagram of client-server requires

 

Image Credit – Udemy Server Side Rendering React JS Flow Diagram

2. SEO friendly : Search Engine crawlers will look for server side rendering because it makes sense for crawlers to communicate with your server to get details of your page ?

3. Social Media Sharing: to get the preview of your page when some one share your page in social media like facebook, server side rendering is must, because facebook/twitter/g+ needs og tags to be filled for the first render itself

After knowing importance of server side rendering, let us explore how to enable it using reactjs.

Important Considerations while working on server side rendering

  1. In reactjs if you are dealing with server side rendering, then you should be aware that most of the component life cycle methods will not be called at server side. if you have to do some operations then you should either do it in component’s constructor or componentWillMount 
  2. And you should keep updating redux store from server side as well and give the updated store to client other wise client is unaware of what is changed in the store

How To Enable Server Side Rendering in React : Calling APIs from server side

Prerequisites for server side rendering in reactjs

  1. Having a nodejs middleware for request handling – if your client part is running on 8080 port and api’s are running on 8081 port, then all the requests coming to 8080 port, should go through this middleware. This is where server side api calls will be handled for every route.
  2. We need a Redux Action for API call which will just return a promise – note here is that, this should not dispatch the state, since its called from server side, the dispatch doesn’t make any sense here.
  3. Static function pointer in a component to redux action -> function pointer will be used to call action from server side
  4. Creating redux store at server side to update the data
  5. Keeping a global state and including it in view ( index.ejs or index.pug whichever view engine you use)

Let us see how to implement server side rendering with reactjs

Define request handler middleware in your app.js : this is where we call apis from backend , observe and understand how we call api for respective route. this is common middleware for all routes, but calling right API for respective route is happening due to routesConfig and static function pointer defined in respective component of routes. To understand this completely check how fetchData function is being used in function handleRender(req, res) and NewsDetailComponent

//App.js

// REQUEST HANDLER FOR SERVER-SIDE RENDERING
const requestHandler = require('./requestHandler');
// requestHandler.js

'use strict';

import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { renderToString } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';

//Reducers combiner 
import reducers from '../src/client/reducers/index';

//All the routes defined 
import routes from '../src/routes';

// Routes config which just has path and respective component mapping
import routesConfigs from '../src/routesConfig';


import DocumentMeta from 'react-document-meta';

//A Wrapper for axios where actual api call happens
import { HTTPRequestHandler } from '../src/util/commonRequires';


function renderView(req, res, state) {
    // STEP-1 CREATE A REDUX STORE ON THE SERVER
    const store = createStore(reducers, state);

  // STEP-2 GET INITIAL STATE FROM THE STORE
  const initialState = JSON.stringify(store.getState()).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--');
  // STEP-3 IMPLEMENT REACT-ROUTER ON THE SERVER TO INTERCEPT CLIENT REQUESTs AND DEFINE WHAT TO DO WITH THEM
  const context = {};
  const reactComponent = renderToString(
    <Provider store={store}>
      <StaticRouter
        location={req.url}
        context={context}>
        {routes}
      </StaticRouter>
    </Provider>
  );
  const reactMetaComponent = DocumentMeta.renderToStaticMarkup();

  if (context.url) {
    // can use the `context.status` that
    // we added in RedirectWithStatus
    redirect(context.status, context.url);
  } else {
    //https://crypt.codemancers.com/posts/2016-09-16-react-server-side-rendering/
    res.status(200).render('index', { reactComponent, reactMetaComponent, initialState });
  }
}
function handleRender(req, res) {
  const components = routesConfigs
    .filter( route => matchPath( req.path, route ) ) // filter matching paths
    .map( route => route.component ); // check if components have data requirement
    let promiseObj = null;    
    if (components.length > 0 && (components[0].fetchData instanceof Function)) {
      components[0]
      .fetchData(req.query)
      .then((response) => {
        //console.log('***--- response ', response);
          renderView(req, res, response);
      })
      .catch((error) => {
        console.log('***--- error ', error);
        renderView(req, res, {});
      });
    } else {
      renderView(req, res, {});
    }
}

module.exports = handleRender;

Check the view part and the most important part because this is where the global redux stare is being shared by client and server
// View Part : index.ejs 
// put below lines of code within the <body> tag

<DIV class = 'appStyle' id="app"><%-reactComponent-%></DIV>
<script>window.INITIAL_STATE=<%- initialState -%></script>

 

Now let us define a component which embed all the routes

// PrimaryLayout.js

import React from 'react';
import { Route, Switch } from 'react-router-dom';
import DocumentMeta from 'react-document-meta';

import MenuComponent from '../components/common/elements/menu';
import NewsDetailComponent from '../components/pages/NewsDetailComponent';

import {
  NEWS
} from '../../constants';


class PrimaryLayout extends React.Component {
  render() {
    const layoutPath = this.props.match.path;
    return (
      <div style={{ paddingTop: 80 }}>
        <MenuComponent />
        <main>
          <Switch>
            <Route exact path={layoutPath} component={LandingPageComponent} />
            <Route exact path={`${layoutPath}${NEWS}/:newsId`} component={NewsDetailComponent} />
          </Switch>
        </main>
      </div>
    );
  }
}

export default PrimaryLayout;

 

Now let us define all routes

//routes.js

'use strict';
// REACT
import React from 'react';

// REACT-ROUTER
//import {Router, Route, IndexRoute, browserHistory} from 'react-router';
import { Route, Switch } from 'react-router-dom';

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { MuiThemeProvider } from 'material-ui/styles';

import PrimaryLayout from './client/containers/PrimaryLayout';


// RETRIVES COMPONENTS BASED ON STATUS
const Status = function ({ code, children }) {
  return (
        <Route
          render={function ({ staticContext }) {
            if (staticContext) {
              staticContext.status = code;
            }
            return children;
          }}
        />
    );
};

//NOT-FOUND COMPONENT
const NotFound = function () {
    return (
      <Status code={404}>
        <div>
          <h2> Sorry, can’t find this page</h2>
        </div>
      </Status>
    );
};

// CLIENT-SERVER SHARED ROUTES
const routes = (
  <MuiThemeProvider muiTheme={getMuiTheme('lightBaseTheme')}>
      <div className='appStyle'>
          {/*
            switch required to handle inclusive rendering,
            example : two different paths like /about /:userName both
            will render both the components switch handles such requests by
            inclusively rendering the specific component
         */}
          <Switch>
            <Route path="/notfound" component={NotFound} />
            <Route path="/" component={PrimaryLayout} />
          </Switch>
      </div>
    </MuiThemeProvider>
    );

export default routes;

 

and let us use the routes

// client.js which defines routes 

'use strict';
// REACT
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
// REACT-ROUTER
import { BrowserRouter } from 'react-router-dom';
//import {Router, Route, IndexRoute, browserHistory} from 'react-router';

import { applyMiddleware, createStore } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import routes from '../routes';


// IMPORT COMBINED REDUCERS
import reducers from './reducers/index';
// STEP 1 create the store
const middleware = applyMiddleware(thunk, logger);
// WE WILL PASS INITIAL STATE FROM SERVER STORE
const initialState = window.INITIAL_STATE;
const store = createStore(reducers, initialState, middleware);

const Routes = (
  <Provider store={store}>
    {/*
      Provider
      Makes the Redux store available to the connect() calls in the component hierarchy below.
      Normally, you can’t use connect() without wrapping a parent or ancestor
      component in
   */}
    {/*
      A <Router> that uses the HTML5 history API (pushState, replaceState and the popstate event)
      to keep your UI in sync with the URL.
    */}
    <BrowserRouter>
      {routes}
    </BrowserRouter>
  </Provider>
);

render(
  Routes, document.getElementById('app')
);

 

New Let us define our component

'use strict';
import React from 'react';
import {connect} from 'react-redux';

import { fetchNews, fetchNewsData } from '../actions/newsActions';

 class NewsDetailComponent extends React.Component {
    constructor(props) {
      super(props);
    }
    
    componentDidMount() {
        this.props.fetchNews(this.props.match.params.eventId);
    }
    render() {
        return(
            <div className='container-fluid'>
                <section>
                    <div className='row'>
                        <div className='col-lg-2 col-md-2 col-sm-2 col-xs-1'></div>
                        <div className='col-lg-8 col-md-8 col-sm-8 col-xs-10'>
                           {/* here your news component */} 
                        </div>
                        <div className='col-lg-2 col-md-2 col-sm-2 col-xs-1'></div>
                    </div>
                </section>
            </div>
        );
    }
 }


function mapStateToProps(state) {
    return {
        newsInfo: state.newsInfo.newsInfo
    };
}
NewsDetailComponent.fetchData = fetchNewsData;
export default connect(mapStateToProps, {
    fetchNews,
})(NewsDetailComponent);

And redux action which calls API

export const fetchNewsData = (params) => {
    return new Promise((resolve, reject) => {
        const newsDetailsUrl = `${NEWS_API_PATH}/${params.newsId}?newsId=${newsId}`;
        HTTPRequestHandler
        .get(newsDetailsUrl)
        .then((apiResponse) => {
            / * 
                Return the updated state so that we can update redux state 
                from server side
            */
            resolve({
                    news: { 
                        news: { 
                            newsDetails: apiResponse.data.newsDetails,
                        } 
                    }
                  });
            
        })
        .catch((apiError) => {
            console.log('-- 2 api call fail--- ', apiError);
            reject(null);
        });
    });
}

Rather than explaining each line of code written, I would like to help you to understand it by taking your attention on important aspects 

  1. to understand how the redux state is managed from backend and available for front end ( UI component, NewsDetailComponent) check how initialState and window.INITIAL_STATE are being used 
  2. to understand how api is called in a common middleware requestHandler at server side for respective page please check how routesConfig , fetchData, fetchNewsData are being used 
  3. to understand how redux store is managed even at server side and synched with client side which is most important – other wise client is unaware of what happened at server side – check function renderView(req, res, state) (server side) and client.js (client side) both are creating redux store but the data from server is being used by client using a global store object.

References : 

https://medium.freecodecamp.org/demystifying-reacts-server-side-render-de335d408fe4

http://sujinc.com/2018/06/20/all-about-sujinc-com-part-1-reactjs-ssr/

 

React Native Crash Undefined is not an object (Evaluating ‘Sn[e]’)

React Native Crash Undefined is not an object (Evaluating ‘Sn[e]’)

Any one facing react native build issue? I am trying to generate debug build but its crashing when the app is launched . The exception has no useful information. I was facing the same issue with

sudo react-native run-android

 

But that got resolved after upgrading RN from 0.48 to 0.55(latest Stable Version). But the crash remain same for the apk generated using

sudo gradlew assembleDebug

The crash is similar to https://github.com/facebook/react-native/issues/16745

please see screenshot

ReactNative Undefined Not an object evaluating

ReactNative Undefined Not an object evaluating

Solution: Generating React Native Android Release and Debug Builds

1. If any one facing issue with generating ReactNative android build then do not forget to follow below steps

2. Update your key store details as given here

3. Then explicitly bundle the assets using below command

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/ 

4. Generate the build using gradle

cd android && ./gradlew assembleRelease

Note: for release build I am facing another issue as follows

Error in Release build :

FAILURE: Build failed with an exception.

* What went wrong:
Failed to capture snapshot of input files for task ‘bundleReleaseJsAndAssets’ property ‘$1’ during up-to-date check.
> Failed to create MD5 hash for file ‘/Development/SourceCode/MobApp/testApp/root-state/sock’.

* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

To generate debug build

cd android && ./gradlew assembleDebug

 

Credits : SO Post

React Native react-navigation props.navigation.navigate(“DrawerOpen”) doesn’t work

React Native react-navigation props.navigation.navigate(“DrawerOpen”) doesn’t work

If you are using react-navigation version “1.0.0-beta.11” then the following apis works fine

props.navigation.navigate('DrawerOpen'); // open drawer
props.navigation.navigate('DrawerClose'); // close drawer

 

If you are using react-navigation version “2.0.0-rc.9” then following apis works fine

props.navigation.openDrawer();
props.navigation.closeDrawer();
props.navigation.toggleDrawer();

 

Read More About React-Navigation Package : react-navigation performance issues

Typical React Native Navigation issues people facing for this

navigation.navigate(‘DrawerOpen’) doesn’t work

DrawerToggle not working on Android #2760

Drawer Menu doesn’t work in react-native

React Native react-navigation navigation.navigate.reset doesn’t work

React Native react-navigation navigation.navigate.reset doesn’t work

1. If you are using react-navigation version “1.0.0-beta.11” then kindly use the below code to reset navigation stack

const resetAction = NavigationActions.reset({
    index: 0,
    key: null,
    actions: [ NavigationActions.navigate({ routeName: 'Home' }) ],
  });
  navigation.dispatch(resetAction);

//Note key: null is very important here.

Reference: github post by react navigation contributor 
2. If you are using react-navigation(v2) version “2.0.0-rc.9” then kindly use the below code to reset navigation stack

const resetAction = StackActions.reset({
    index: 0,
    key: null,
    actions: [ NavigationActions.navigate({ routeName: 'DrawerStack' }) ],
  });
  navigation.dispatch(resetAction);

 

Read More On React-Navigation : Typical issues of react-navigation

React Native react-navigation performance issue: Optimising performance

React Native react-navigation performance issue: Optimising performance

Rather than writing a detailed article here, I would like to point out very few performance tuning technique with respect to React Native Navigation using react-navigation package.

1. Few check you have to do before blaming react-navigation library, Check whether are you calling any location api to fetch current location.

If you are fetching current location on component mount or will mount then consider my suggestion , fetch the current location on launch of app and save the location, then onwards use the saved location rather than fetching current location every time.

Find the code here to do so

import { AsyncStorage } from 'react-native';

let instance = null;
class SharedPreferences {

  constructor() {
    if (!instance) {
      instance = this;
    }
    return instance;
  }
  async put(key, val) {
    try {
      await AsyncStorage.setItem(key, val);
    } catch (error) {
      console.error('Unable to save in preferences: ', error);
    }
  }

  async get(key) {
    try {
      return await AsyncStorage.getItem(key);
    } catch (error) {
      console.error('Unable to get from preferences: ', error);
    }
  }

   getMultiple(keys, callback) {
     AsyncStorage.multiGet(keys, (err, stores) => {
       if (!err) {
         const keyVals = {};
         stores.map((result, i, store) => {
           keyVals[`${result[0]}`] = result[1];
         });
         callback(keyVals);
       } else {
         callback([]);
       }
     });
  }
}

const sharedPreference = new SharedPreferences();

export const SHARED_PREFERENCE = {
  accessor: sharedPreference
};
'use strict';

import { SHARED_PREFERENCE } from './SharedPreferences';
import { SHARED_PREFERENCE_KEYS } from './AppConstants';

const defaultLocation = {
  coords: {
    latitude: 12.9833,
    longitude: 77.5833
  }
};

export function getCurrentLocation(navigator, callback) {
  SHARED_PREFERENCE.accessor.get(SHARED_PREFERENCE_KEYS.LAST_SAVED_LOCATION_ID)
  .then(savedLocation => {
    if (savedLocation !== null && savedLocation !== undefined) {
      const location = JSON.parse(savedLocation);
      console.log('Returning Saved Location');
      callback(location);
    } else {
      navigator
      .geolocation.getCurrentPosition(
        (location) => {
          console.log(`Saving Device Current Location due to failed save in last try:
             ${JSON.stringify(location)}`);
          SHARED_PREFERENCE
          .accessor
          .put(LAST_SAVED_LOCATION_ID, JSON.stringify(location));
          callback(location);
        }, (geoError) => {
          callback(defaultLocation);
        },
        { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 });
    }
  })
  .catch((locationError) => {
    callback(defaultLocation);
  });
}

export function saveCurrentLocation(navigator) {
  navigator
  .geolocation.getCurrentPosition(
    (location) => {
      console.log(`Saving Device Current Location: ${JSON.stringify(location)}`);
      SHARED_PREFERENCE
      .accessor
      .put(LAST_SAVED_LOCATION_ID, JSON.stringify(location));
    }, (geoError) => {
      console.log(`Save Location Failed. ${JSON.stringify(geoError)}`);
    },
    { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 });
}

2. Use Stateless components than ReactComponents wherever it is possible : Read more about StateLessComponents

3. Upgrade react-navigation package from “1.0.0-beta.11” to “2.0.0-rc.9” : This will boost the performance of react-navigation .

React Native Social Authentication Using Firebase: Google+ and Facebook Signin, Signup – A Step by Step Guide

React Native Social Authentication Using Firebase: Google+ and Facebook Signin, Signup – A Step by Step Guide

One has to go through following steps to enable social authentication in their react native mobile apps. In this tutorial we will see how to enable react native social login for android applications.

React Native Google Plus Signup/Signin Using Firebase Authentication

1. Create Project in Google Cloud Platform : Try free trail 

2. Enable Google+ API for your project and generate API Key

GCloudApiKey1

GCloudApiKey1

3. Set YourSHA-1 key and package name (as given in AndroidManifest.xml ) of your android project

To generate your own SHA-1 use the command -> keytool -list -v -keystore mystore.keystore

NOTE : If Your build is debug build then theSHA-1 generated with above command won’t work, kindly check your adb logs carefully, theSHA-1 being used by your android debug build will be logged in the device log. To check device log run the below command from your /Users/<YourSystemUserName>/Library/Android/sdk/platform-tools —> adb logcat

APIKey&SHA1

APIKey&SHA1

4. Import the same project in firebase

ImportProjectFirebase

ImportProjectFirebase

5. Setup android project in your firebase project, then setup authentication methods being used in your app.

firebaseAuthMethods

firebaseAuthMethods

6. Then setup sameSHA-1 Key for your firebase project: Navigate to Project setting from side bar and click on general , select android app and set SHA-1 key

NOTE: Once SHA-1 is setup, download google-services.json file in the same page. and keep the file under your android project director app folder /ReactNativeProjectFolder/android/app

Till this your google cloud and firebase setup is done, now we have to do lot of changes in code.

7. add ‘react-native-google-signin’ and ‘firebase’ modules

npm install react-native-google-signin –save

npm install firebase –save

8. Add dependency in your /app/bundle.gradle

Note : in below code those excludes are most important, or else you will encounter strange linking errors.

implementation project(':react-native-google-signin')

if your app is using some other dependencies like react-native-maps or react-native-social-share then do below changes as well

implementation(project(":react-native-google-signin")){
    exclude group: "com.google.android.gms" // very important
}
compile(project(':react-native-maps')) {
      exclude group: 'com.google.android.gms', module: 'play-services-base'
      exclude group: 'com.google.android.gms', module: 'play-services-maps'
    }
implementation 'com.google.android.gms:play-services-base:11.+'
implementation 'com.google.android.gms:play-services-maps:11.+'

9. your android/bundle.gradle file should look as follows

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath 'com.google.gms:google-services:3.0.0' // &lt;--- add this
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        mavenLocal()
        jcenter()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
    }
}

ext {
    compileSdkVersion   = 23
    targetSdkVersion    = 23
    buildToolsVersion   = "23.0.1"
    googlePlayServicesVersion = "10.2.4"
    androidMapsUtilsVersion = "0.5+"
}

 

10. run below commands

npm install

react-native link

11. Once you run react native link – check android/settings.gradle file , cross check that there should not be duplicate lines of content.

So far we have done project level configurations, now let us see code changes

12. React Native Google sign-in/sign-up using firebase code

import { GoogleSignin } from 'react-native-google-signin';
import firebase from 'firebase';

function googleAuthConfig(successCallback, failureCallback) {
  /*
   Web Client id 
      Get the client_id from Google-services.json file, in that file under 
    "client": [
       "oauth_client": [
        {
          "client_id": "", //This you have to use as webClientId and the same for android
          "client_type": 3
        }
       
  */
  GoogleSignin.configure({
    iosClientId: CLIENT_IDS.GOOGLE_IOS_CLIENT_ID,
    webClientId: '',
    hostedDomain: '', // specifies a hosted domain restriction
    forceConsentPrompt: true, // [Android] if you want to show the authorization prompt at each login
    accountName: '' // [Android] specifies an account name on the device that should be used
  })
  .then(() =&gt; {
    console.log('Google Config Success');
    successCallback();
  })
  .catch((err) =&gt; {
    console.log('Google Config Error');
    failureCallback(err);
  });
}


function googleSignin() {
  googleAuthConfig(() =&gt; {
      GoogleSignin.signIn()
      .then((user) =&gt; {
        const { accessToken } = user;
          var credentials = firebase.auth.GoogleAuthProvider.credential(null, accessToken);
          firebase.auth().signInWithCredential(credentials)
          .then((firebaseResult) =&gt; {
            loginToSG(dispatch, firebaseResult, props, 'Google', registerCallback);
          })
          .catch(error =&gt; console.log('error while checking with firebase', error));
      })
      .catch((err) =&gt; {
        console.log(err);
        });
    }, (googleConfigErr) =&gt; {
        console.log(googleConfigErr);
    });
}

13. Finally the most important step is -> once do npm cache clean, delete your existing app from device, delete build folders then run the app 

react-native run-android 

React Native: Ejecting Expo To Regular React Native Project.

React Native: Ejecting Expo To Regular React Native Project.

Before explaining the steps for eject from expo, I would like to thank the expo community who has done really a great job, it was nightmare for us to start with ReactNative initially without expo. Expo has done remarkable job and simplified the whole process to us. So we should thank expo community for that. But Expo has come up with its own limitations, it is really difficult to go forward with those limitations, hence ejecting from expo is must.

Follow below steps and find the issues listed in each step and the solutions for the issues faced during eject process. Follow all the below steps

1. npm run eject

<span style="color: #000000;">? How would you like to eject from create-react-native-app? (Use arrow keys)
❯ React Native: I'd like a regular React Native project. 
  ExpoKit: I'll create or log in with an Expo account to use React Native and the Expo SDK. 
  Cancel: I'll continue with my current project structure. 
Choose 1st option</span>

2. then run the command

react-native run-android
Building and installing the app on the device (cd android && ./gradlew installDebug)…

Problem:
FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ‘:app’.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.

* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

BUILD FAILED

Total time: 45.174 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

Solution:
Create local.properties in the andoid project folder and save the below content in that
sdk.dir = /Users/USERNAME/Library/Android/sdk
USERNAME: USERNAME should be your maachine user name

3. run the command

$ sudo react-native run-android

Problem:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ‘:app:installDebug’.
> com.android.builder.testing.api.DeviceException: No connected devices!

* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

BUILD FAILED

Total time: 6.945 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

   Solution : Use proper cable and connect your device, enable debug mode in your android device. this is problem with some devices, do not spend time on this, because you will face bigger problems later 🙂 so either change the device or try with different cable.

4. Problem
com.android.ddmlib.InstallException: Failed to install all
at com.android.ddmlib.SplitApkInstaller.install(SplitApkInstaller.java:89)
at com.android.ddmlib.Device.installPackages(Device.java:904)
at com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:137)
at com.android.build.gradle.internal.tasks.InstallVariantTask.install(InstallVariantTask.java:134)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:228)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:621)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:604)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153)
at org.gradle.internal.Factories$1.create(Factories.java:22)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99)
at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46)
at org.gradle.launcher.exec.DaemonUsageSuggestingBuildActionExecuter.execute(DaemonUsageSuggestingBuildActionExecuter.java:51)
at org.gradle.launcher.exec.DaemonUsageSuggestingBuildActionExecuter.execute(DaemonUsageSuggestingBuildActionExecuter.java:28)
at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:43)
at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:173)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:239)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:212)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:205)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
at org.gradle.launcher.Main.doAction(Main.java:33)
at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:55)
at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:36)
at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:30)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:127)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)
:app:installDebug FAILED

Solution:
update gradle version in build.gradle file of your android project
classpath ‘com.android.tools.build:gradle:3.0.1’

5.

Problem
Building and installing the app on the device (cd android && ./gradlew installDebug)…

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project ‘testApp’.
> Could not resolve all dependencies for configuration ‘:classpath’.
> Could not find com.android.tools.build:gradle:3.0.1.
Searched in the following locations:
https://jcenter.bintray.com/com/android/tools/build/gradle/3.0.1/gradle-3.0.1.pom
https://jcenter.bintray.com/com/android/tools/build/gradle/3.0.1/gradle-3.0.1.jar
Required by:
:testApp:unspecified

* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

BUILD FAILED

Total time: 10.721 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

Solution:
add google() to your build script, as follows

buildscript {
    repositories {
        google()
        jcenter()
    }

 

6. Problem

FAILURE: Build failed with an exception.

* Where:
Build file ‘/testapp/android/build.gradle’ line: 5

* What went wrong:
A problem occurred evaluating root project ‘testApp’.
> Could not find method google() for arguments [] on repository container.

* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

BUILD FAILED

Total time: 1.973 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

Solution:
in your android/gradle/wrapper/gradle-wrapper.properties file check whether you have gradle distribution version 4,
it should be as follow.

distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

7. After this build success
8. Now facing Run-time exception of something like this

react android run Couldn’t find preset\ babel-preset-react native stage 0

error: bundling failed: “TransformError: D:\\path\\path\\project\\index.android.js: Unex
pected token ) (While processing preset: \”D:\\\\path\\\\path\\\\project\\\\node_modules
\\\\babel-preset-react-native\\\\index.js\”)”

Solution : Remove “babel-preset-react-native-stage-0/decorator-support” from your .bablerc file, Your bablerc file should look as follows

{
  "presets": [
    "react-native"
  ],
  "env": {
    "development": {
      "plugins": [
        "transform-react-jsx-source"
      ]
    }
  }
}

React Native Android Build: Exception After Ejecting(Detaching) Expo with ExpoKit

React Native Android Build: Exception After Ejecting(Detaching) Expo

After so much struggle resolved all the build issues for React Native Android build after ejecting expo but using ExpoKit. Now getting android runtime exception, the app crashes as soon as it is launched. Exception is as follows.

React Native Android Runtime Exception

E/AndroidRuntime(17278): Process: com.company.testapp, PID: 17278
E/AndroidRuntime(17278): java.lang.NoClassDefFoundError: Failed resolution of: Lbolts/AppLinks;
E/AndroidRuntime(17278): 	at com.facebook.appevents.internal.SourceApplicationInfo$Factory.create(SourceApplicationInfo.java:131)
E/AndroidRuntime(17278): 	at com.facebook.appevents.internal.ActivityLifecycleTracker.onActivityCreated(ActivityLifecycleTracker.java:131)
E/AndroidRuntime(17278): 	at com.facebook.appevents.internal.ActivityLifecycleTracker$1.onActivityCreated(ActivityLifecycleTracker.java:77)
E/AndroidRuntime(17278): 	at android.app.Application.dispatchActivityCreated(Application.java:189)
E/AndroidRuntime(17278): 	at android.app.Activity.onCreate(Activity.java:952)
E/AndroidRuntime(17278): 	at android.support.v4.app.SupportActivity.onCreate(SupportActivity.java:66)
E/AndroidRuntime(17278): 	at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:297)
E/AndroidRuntime(17278): 	at host.exp.exponent.experience.ReactNativeActivity.onCreate(ReactNativeActivity.java:130)
E/AndroidRuntime(17278): 	at host.exp.expoview.ExponentActivity.onCreate(ExponentActivity.java:69)
E/AndroidRuntime(17278): 	at android.app.Activity.performCreate(Activity.java:6120)
E/AndroidRuntime(17278): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1112)
E/AndroidRuntime(17278): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2467)
E/AndroidRuntime(17278): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2600)
E/AndroidRuntime(17278): 	at android.app.ActivityThread.access$800(ActivityThread.java:177)
E/AndroidRuntime(17278): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1469)
E/AndroidRuntime(17278): 	at android.os.Handler.dispatchMessage(Handler.java:111)
E/AndroidRuntime(17278): 	at android.os.Looper.loop(Looper.java:194)
E/AndroidRuntime(17278): 	at android.app.ActivityThread.main(ActivityThread.java:5622)
E/AndroidRuntime(17278): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(17278): 	at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(17278): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
E/AndroidRuntime(17278): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
E/AndroidRuntime(17278): Caused by: java.lang.ClassNotFoundException: Didn't find class "bolts.AppLinks" on path: DexPathList[[zip file "/data/app/com.company.testapp-1/base.apk"],nativeLibraryDirectories=[/data/app/com.company.testapp-1/lib/arm, /vendor/lib, /system/lib]]
E/AndroidRuntime(17278): 	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
E/AndroidRuntime(17278): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
E/AndroidRuntime(17278): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
E/AndroidRuntime(17278): 	... 22 more
E/AndroidRuntime(17278): 	Suppressed: java.lang.ClassNotFoundException: bolts.AppLinks
E/AndroidRuntime(17278): 		at java.lang.Class.classForName(Native Method)
E/AndroidRuntime(17278): 		at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
E/AndroidRuntime(17278): 		at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
E/AndroidRuntime(17278): 		at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
E/AndroidRuntime(17278): 		... 23 more
E/AndroidRuntime(17278): 	Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
V/SettingsInterface(  765):  from settings cache , name = dropbox:data_app_crash , value = null
V/SettingsInterface(  765):  from settings cache , name = send_action_app_error , value = 1
D/ActivityManager(  765): SVC-mBroadcastQueues: com.android.server.am.BroadcastQueue@29a56dae
D/ActivityManager(  765): SVC-mBroadcastQueues: com.android.server.am.BroadcastQueue@256ee74f
W/ActivityManager(  765):   Force finishing activity 1 com.company.testapp/.MainActivity

 

Solution

Finding the solution… Will update it soon here.

React Native Building In Android and iOS: After Ejecting(Detaching) Expo with ExpoKit

React Native Building In Android and iOS: After Ejecting(Detaching) Expo

I am trying to build React Native app for android and iOS but keep finding one and other issues. After so much struggle I succeeded with initial hickups but now struck at one point where I am not finding any solution.

Problems I am facing with React Native Build For Android and iOS , before encountering the issue I followed the below steps

1. Install Cocoapods (https://cocoapods.org/)
2. Run pod install from your project’s ios directory.
3. Run ‘react-native run-ios’ in the project root folder.
4. Run ‘react-native run-android’ in the project root folder.

After running react-native run-android I am getting below error.

:app:transformClassesWithJarMergingForDebug 
FAILED

FAILURE: Build failed with an exception.

* What went wrong:

Execution failed for task ':app:transformClassesWithJarMergingForDebug'.

com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/google/android/gms/auth/api/signin/zzc.class
* Try:

Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 25.103 secs

Could not install the app on the device, read the error above for details.

Make sure you have an Android emulator running or a device connected and have

set up your Android development environment:

https://facebook.github.io/react-native/docs/android-setup.html

————————————————————————————————————————————————————————————————————————

My app gradle file looks as follows

<span style="color: #3366ff;">apply plugin: 'com.android.application'

android {
  compileSdkVersion 26
  buildToolsVersion '26.0.2'

  defaultConfig {
    applicationId "com.mycompany.testapp"
    minSdkVersion 20
    targetSdkVersion 25
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    ndk {
      abiFilters 'armeabi-v7a', 'x86'
    }
    manifestPlaceholders = [
      'appAuthRedirectScheme': 'com.mycompany.testapp'
    ]
  }
  buildTypes {
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
  dexOptions {
    javaMaxHeapSize "8g"
  }
}

task exponentPrebuildStep(type: Exec) {
  workingDir '../../'

  if (System.getProperty('os.name').toLowerCase().contains('windows')) {
    commandLine 'cmd', '/c', '.\\.expo-source\\android\\detach-scripts\\prepare-detached-build.bat'
  } else {
    commandLine './.expo-source/android/detach-scripts/prepare-detached-build.sh'
  }
}
preBuild.dependsOn exponentPrebuildStep

repositories{
  flatDir{
    dirs 'libs'
  }
  mavenLocal()
  maven { url 'https://maven.fabric.io/public' }
}

dependencies {
    compile project(':react-native-social-share')
    compile project(':react-native-maps')
    compile project(':react-native-vector-icons')
  compile fileTree(dir: 'libs', include: ['*.jar'])
  testCompile 'junit:junit:4.12'
  compile 'com.android.support:appcompat-v7:25.3.1'
  compile 'com.android.support:multidex:1.0.1'

  compile 'com.google.firebase:firebase-core:10.0.1'
  compile 'com.google.firebase:firebase-auth:10.0.0'
  compile 'com.google.android.gms:play-services-auth:10.2.1'

  compile('host.exp.exponent:expoview:21.0.0@aar') {
    exclude group: 'com.facebook.android', module: 'facebook-android-sdk'
    exclude group: 'com.facebook.android', module: 'audience-network-sdk'
    exclude group: 'io.nlopez.smartlocation', module: 'library'
    transitive = true;
  }

  compile ('com.facebook.android:facebook-android-sdk:4.+') {

  }
  compile('com.facebook.android:audience-network-sdk:4.+') {
    exclude module: 'play-services-ads'
  }
  compile('io.nlopez.smartlocation:library:3.2.11') {
    transitive = false
  }
}
</span>

 

Solution:

The solution is to find the conflicting dependencies using following command inside your app/android folder

$ ./gradlew app:dependencies

Closely observe the dependency hierarchy and check the conflicted dependency for com.google.android.gms. To resolve this you have to exclude it for specific dependency as follows, see the updated build.gradle file

apply plugin: 'com.android.application'

android {
  compileSdkVersion 26
  buildToolsVersion '26.0.1'

  defaultConfig {
    applicationId "com.mycompany.testapp"
    minSdkVersion 19
    targetSdkVersion 25
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    ndk {
      abiFilters 'armeabi-v7a', 'x86'
    }
    manifestPlaceholders = [
      'appAuthRedirectScheme': 'com.mycompany.testapp'
    ]
  }
  buildTypes {
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
  dexOptions {
    javaMaxHeapSize "8g"
  }
}

task exponentPrebuildStep(type: Exec) {
  workingDir '../../'

  if (System.getProperty('os.name').toLowerCase().contains('windows')) {
    commandLine 'cmd', '/c', '.\\.expo-source\\android\\detach-scripts\\prepare-detached-build.bat'
  } else {
    commandLine './.expo-source/android/detach-scripts/prepare-detached-build.sh'
  }
}
preBuild.dependsOn exponentPrebuildStep

repositories{
  flatDir{
    dirs 'libs'
  }
  mavenLocal()
  maven { url 'https://maven.fabric.io/public' }
}

dependencies {
  compile project(':react-native-vector-icons')
  compile(project(':react-native-maps')){
      exclude group: 'com.google.android.gms'
  }

  compile fileTree(dir: "libs", include: ["*.jar"])
  compile 'com.android.support:appcompat-v7:25.3.1'
  compile "com.facebook.react:react-native:+"  // From node_modules
  compile ("com.google.android.gms:play-services-base:10.0.1") {
      force = true;
  }
  compile ("com.google.android.gms:play-services-maps:10.0.1") {
      force = true;
  }
  compile ("com.google.android.gms:play-services-gcm:10.0.1") {
      force = true;
  }
  compile ('com.google.firebase:firebase-core:10.0.1') {
      force = true;
  }


  testCompile 'junit:junit:4.12'

  compile project(':react-native-vector-icons')

  compile(project(':react-native-social-share')){
        exclude group: 'com.google.android.gms'
  }

  compile('host.exp.exponent:expoview:21.0.0@aar') {
    exclude group: 'com.facebook.android', module: 'audience-network-sdk'
    exclude group: 'io.nlopez.smartlocation', module: 'library'
    exclude group: 'com.google.android.gms'
    transitive = true;
  }

  compile('com.facebook.android:audience-network-sdk:4.+') {
    exclude module: 'play-services-ads'
  }
  compile('io.nlopez.smartlocation:library:3.2.11') {
    transitive = false
  }


}

React Native Android Build Failure : failed to find Build Tools revision 26.0.1 or failed to find Build Tools revision 23.0.1

React Native Android Build Failure : failed to find Build Tools revision 26.0.1 or failed to find Build Tools revision 23.0.1

If you are facing following exception

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':app'.
&gt; A problem occurred configuring project ':react-native-vector-icons'.
   &gt; failed to find Build Tools revision 26.0.1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 2 mins 44.097 secs
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html

Or the exception may be for Build Tools revision 23.0.1

Then Kindly install build tools versions from your android studio. 

Go to android studio Preferences, select second tab SDK Tools, Install respective build tool version. Do not forget to check mark Show Package Details in the dailog box. Refer below screenshot

ReatNativeAndroidExceptionBuildToolsrevision

ReatNativeAndroidExceptionBuildToolsrevision