Как перезапустить реагирующее нативное приложение через глубокую ссылку

Я пытаюсь внедрить глубокую ссылку в свое родное приложение для Android. Ссылка отправляется через SMS, и при нажатии на ссылку открывается приложение, и на основе URL-адреса я перехожу к определенному экрану, используя android:launchMode="singleTop". Проблема, с которой я столкнулся, заключается в том, что при нажатии на ссылку открывается новый экземпляр приложения, а я этого не хотел, поэтому я изменил android:launchMode="singleTask" на мой activity в AndroidManifest.xml, и теперь есть только один экземпляр. Но теперь, когда нажимается ссылка из SMS, она возобновляет существующую страницу, и я не могу щелкнуть URL-адрес.

Я реализовал «AppState», чтобы знать, когда экран возобновляется, но это также не дает мне URL-адрес.

Чего я хочу достичь, так это либо

  • Приложение полностью перезапускается с самого начала Splash activity, и я знаю, что могу получить URL-адрес и перейти оттуда на основе URL-адреса. (android:launchMode="singleTop" не перезапускает приложение, а открывает новый экземпляр)
  • Или, когда пользователь нажимает на URL-ссылку, даже если он возобновляет существующий экран, я хочу получить URL-адрес и перейти к определенному экрану.

Манифест

   <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>

Ссылка, которая отправляется в виде SMS - http://abcd/createpassword

Заставка — начальный экран.

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);
    }       
}

Вышеупомянутая установка отлично работает с android:launchMode="singleTop", но проблема только в том, что мне не нужен новый экземпляр приложения.

Итак, я попробовал следующие изменения

Манифест

android:launchMode="singleTask"

При этом есть только один экземпляр, и при нажатии на URL-адрес приложение возобновляет работу.

Поэтому я добавил AppState на страницу, которая возобновляется, и попытался получить URL-адрес, но это не сработало.

  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);
    }       
  }

Пожалуйста, предложите.

Спасибо Р


comment
Вы нашли решение?   -  person Simon    schedule 17.01.2019
comment
Привет @Simon, я добавляю ответ здесь. дайте мне знать, если это поможет. Теперь у меня все работает, поэтому дайте мне знать, если у вас есть какие-либо вопросы   -  person BRDroid    schedule 24.01.2019
comment
Спасибо за вашу помощь. К сожалению, нам больше не нужна функция deeplinking. Но я очень ценю вашу помощь.   -  person Simon    schedule 29.01.2019
comment
не беспокойся @Саймон   -  person BRDroid    schedule 29.01.2019


Ответы (1)


Вот решение, которое работает для меня.

режим запуска, который я установил на singleTask Manifest.xml

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

Начальный экран, который открывается в моем приложении, — это экран-заставка. Допустим, вы получили SMS, и ваше приложение закрыто, мы снова откроем приложение, чтобы оно всегда открывало начальный экран в заставке моего случая.

Вот мой код заставки.

    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
        }       
    }

И на других экранах, когда приложение открыто и получено сообщение. вы нажимаете на ссылку, и она открывает тот же экран. Поэтому на этом экране требуется следующая логика.

    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
          }

      }

Надеюсь, поможет.

дайте мне знать, если вам нужна дополнительная информация

Спасибо Р

person BRDroid    schedule 24.01.2019
comment
спасибо, в IOS Linking работает как шарм, но в Android в любое время URL-адрес вызывает перезапуск приложения, но после добавления android:launchMode=singleTask в AndroidManifest.xml действует как ios. - person Moein Hosseini; 12.06.2019