BRDroid
BRDroid

Reputation: 4388

How to restart react native app through deep linking

I am trying to implement deeplinking in my react native Android application. Link is sent through and SMS and when the link is clicked it opens the app and based on the url I am navigating to a perticular screen using android:launchMode="singleTop". The issue I was facing is when the link is clicked, a new instance of the app is opened and I did not want that so I changed to android:launchMode="singleTask" to my activity in AndroidManifest.xml and now there is only one instance. But now when the link from the SMS is clicked it resumes the existing page and I cannot get the url clicked.

I implemented 'AppState' to know when a screen is resumed but that does not give me the url too.

What I want to be able to achieve is either

Manifest

   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.abcdabcdapp">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        //This is what is required to open from the link
        <intent-filter android:label="ABCD App">
          <action android:name="android.intent.action.VIEW" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="android.intent.category.BROWSABLE" />
          <data 
            android:scheme="http"
            android:host="abcd"
            android:pathPrefix="/createpassword" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>
</manifest>

Link that is sent through as SMS - http://abcd/createpassword

Splash screen - Initial screen.

componentDidMount() {
        setTimeout(() => {
            this.whereShoulINavigateTo();
        }, 2500);        
    }

whereShoulINavigateTo = async () => {
    if (Platform.OS === 'android') {
        Linking.getInitialURL().then( async (url) => {
          //this.navigate(url);
          if(url === 'http://abcd/createpassword')
          { 
            this.props.navigation.navigate('CreatePasswordScreen');
          }else{
            //do something
          }
        });
      } else {
          alert('ios url -' + url );
          //Linking.addEventListener('url', this.handleOpenURL);
    }       
}

Above setup works fine with android:launchMode="singleTop" but only issue is I donot want a new instance of the app.

So I tried the following changes

Manifest

android:launchMode="singleTask"

With this there is only one instance and when the URL is clicked, app resumes.

So I added AppState to the page which resumes and tried to get the URL but that did not work.

  componentDidMount(){
    //this.whereShoulINavigateTo();       
    AppState.addEventListener('change', this._handleAppStateChange);
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }

  _handleAppStateChange = (nextAppState) => {
    if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
      console.log('App has come to the foreground!')
      this.whereShoulINavigateTo();   
    }
    this.setState({appState: nextAppState});
  }

  whereShoulINavigateTo = async () => {
    if (Platform.OS === 'android') {
        Linking.getInitialURL().then( async (url) => {
          alert('url - ' + url)
          if(url === 'http://abcd/createpassword')
          { 
            this.props.navigation.navigate('CreatePasswordScreen');
          }
        });
      } else {
          alert('ios url -' + url );
          //Linking.addEventListener('url', this.handleOpenURL);
    }       
  }

Please suggest.

Thanks R

Upvotes: 0

Views: 2476

Answers (2)

Mohamed suja
Mohamed suja

Reputation: 43

Delete the /android folder and expo

run "expo prebuild" command and build it.

Upvotes: 0

BRDroid
BRDroid

Reputation: 4388

Here is the solution that works for me.

launch mode I have set it to singleTask Manifest.xml

       <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
            android:windowSoftInputMode="adjustResize">

The initial screen that opens in my app is Splash screen. Lets say you received the SMS and your app is closed we will reopen the app so it will always open the initial screen in my case splash screen.

Here is my splash screen code.

    componentDidMount() {
        setTimeout(() => {
            this.whereShoulINavigateTo();
        }, 2500);        
    }

    whereShoulINavigateTo = async () => {
        encryptString('abcd');
        decryptString('abcd');
        if (Platform.OS === 'android') {
            Linking.getInitialURL().then( async (url) => {               
                if(url === 'http://abcd/1234')
                { 
                    //if the url is right do something
                }else{

                }
            });
          } else {
              alert('ios url -' + url );
              //Linking.addEventListener('url', this.handleOpenURL);
              //Not implemented for iOS yet
        }       
    }

And on the other screens when the app is open and a message is received. you click on the link and it open the same screen. So following logic is required on that screen.

    componentDidMount(){
        Linking.addEventListener('url', this.handleOpenURL);
      }  

      componentWillUnmount() {
        Linking.removeEventListener('url', this.handleOpenURL);
      }

       handleOpenURL = async (event) => { 
        consoleLog('url - ' + event.url);      
          if(event.url === 'http://abcd/1234')
          { 
              //if the url is right do something
          }

      }

Hope it helps.

let me know if you need any further info

Thanks R

Upvotes: 3

Related Questions