Search code examples
react-nativeauthenticationsessioncookiesreact-native-webview

How to keep last web session active in react-native-webview?


I am working on one app, In which I need to keep users last web-session active in react-native-webview.

Here is a required work-flow.

  • My app is only have one WebView, Where there is fixed url is loading.

  • User will open app & login to that website.

  • When user will kill app & open it again, I need to keep that user logged in as he has already logged in last time.

Here is what i tried so far:

// list cookies (IOS ONLY)

CookieManager.getAll(useWebKit)
    .then((res) => {
        console.log('CookieManager.getAll from webkit-view =>', res);
    });

But as it's suggested, It'll only work in iOS. I am also not able to set that cookies in website that is opened in WebView to keep that session active.

But I didn't found any success yet.

Any suggestion or solution will highly appreciated.

======= Update =======

For Android:

It is working by default, That means we only need to check this for iOS.


Solution

  • actually this problem exist in react-native-webview

    Cookies are lost on iOS after application closing

    it should be resolve through native code. but today I made a solution and tested with PHP website

    Full Code

    import React, {Component} from 'react';
    import {StyleSheet, SafeAreaView} from 'react-native';
    import {WebView} from 'react-native-webview';
    import CookieManager from '@react-native-community/cookies';
    import AsyncStorage from '@react-native-community/async-storage';
    
    let domain="http://example.com";
    
    export default class App extends Component {
      constructor(props) {
        super(props);
        this.currentUrl = '';
        this.myWebView = React.createRef();
        this.state = {
          isReady: false,
          cookiesString: '',
        };
      }
    
      jsonCookiesToCookieString = (json) => {
        let cookiesString = '';
        for (let [key, value] of Object.entries(json)) {
          cookiesString += `${key}=${value.value}; `;
        }
        return cookiesString;
      };
    
      componentWillMount() {
        this.provideMeSavedCookies()
          .then(async (savedCookies) => {
            let cookiesString = this.jsonCookiesToCookieString(savedCookies);
            const PHPSESSID = await AsyncStorage.getItem('PHPSESSID');
            if (PHPSESSID) {
              cookiesString += `PHPSESSID=${PHPSESSID};`;
            }
            this.setState({cookiesString, isReady: true});
          })
          .catch((e) => {
            this.setState({isReady: true});
          });
      }
    
      onLoadEnd = (syntheticEvent) => {
        let successUrl = `${domain}/report.php`;
        if (this.currentUrl === successUrl) {
          CookieManager.getAll(true).then((res) => {
            AsyncStorage.setItem('savedCookies', JSON.stringify(res));
            if (res.PHPSESSID) {
              AsyncStorage.setItem('PHPSESSID', res.PHPSESSID.value);
            }
          });
        }
      };
      onNavigationStateChange = (navState) => {
        this.currentUrl = navState.url;
      };
    
    
      provideMeSavedCookies = async () => {
        try {
          let value = await AsyncStorage.getItem('savedCookies');
          if (value !== null) {
            return Promise.resolve(JSON.parse(value));
          }
        } catch (error) {
          return {}
        }
      };
    
      render() {
        const {cookiesString, isReady} = this.state;
        if (!isReady) {
          return null;
        }
        return (
          <SafeAreaView style={styles.container}>
            <WebView
              ref={this.myWebView}
              source={{
                uri: `${domain}`,
                headers: {
                  Cookie: cookiesString,
                },
              }}
              scalesPageToFit
              useWebKit
              onLoadEnd={this.onLoadEnd}
              onNavigationStateChange={this.onNavigationStateChange}
              sharedCookiesEnabled
              javaScriptEnabled={true}
              domStorageEnabled={true}
              style={styles.WebViewStyle}
            />
          </SafeAreaView>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: '#FFF',
      },
      WebViewStyle: {
        flex: 1,
        resizeMode: 'cover',
      },
    });
    

    Detail:

    Step 1:

    get cookies after login and save in AsyncStorage like this

    onNavigationStateChange = (navState) => {
        this.currentUrl = navState.url;
      };
    
     onLoadEnd = () => {
        let successUrl = `${domain}/report.php`;
        if (this.currentUrl === successUrl) {
          CookieManager.getAll(true).then((res) => {
            AsyncStorage.setItem('savedCookies', JSON.stringify(res));
            if (res.PHPSESSID) {
              AsyncStorage.setItem('PHPSESSID', res.PHPSESSID.value);
            }
          });
        }
      };
    

    Step 2:

    enable sharedCookiesEnabled props and get saved cookies in componentWillMount and make required webview header cookies formate by jsonCookiesToCookieString function and stop render webview by isReady props utils you get cookies

    jsonCookiesToCookieString = (json) => {
        let cookiesString = '';
        for (let [key, value] of Object.entries(json)) {
          cookiesString += `${key}=${value.value}; `;
        }
        return cookiesString;
      };
    
    provideMeSavedCookies = async () => {
        try {
          let value = await AsyncStorage.getItem('savedCookies');
          if (value !== null) {
            return Promise.resolve(JSON.parse(value));
          }
        } catch (error) {
          return {}
        }
      };
    
    componentWillMount() {
        this.provideMeSavedCookies()
          .then(async (savedCookies) => {
            let cookiesString = this.jsonCookiesToCookieString(savedCookies);
            const PHPSESSID = await AsyncStorage.getItem('PHPSESSID');
            if (PHPSESSID) {
              cookiesString += `PHPSESSID=${PHPSESSID};`;
            }
            this.setState({cookiesString, isReady: true});
          })
          .catch((e) => {
            this.setState({isReady: true});
          });
      }
    

    Step 3:

    pass cookiesString in Webview Header and write render function like this

    render() {
        const {cookiesString, isReady} = this.state;
        if (!isReady) {
          return null;
        }
        return (
          <SafeAreaView style={styles.container}>
            <WebView
              ref={this.myWebView}
              source={{
                uri: `${domain}`,
                headers: {
                  Cookie: cookiesString,
                },
              }}
              scalesPageToFit
              useWebKit
              onLoadEnd={this.onLoadEnd}
              onNavigationStateChange={this.onNavigationStateChange}
              sharedCookiesEnabled
              javaScriptEnabled={true}
              domStorageEnabled={true}
              style={styles.WebViewStyle}
            />
          </SafeAreaView>
        );
      }