Sergei
Sergei

Reputation: 550

Interact with React app in Android WebView

Here is my simplified setup

//--- sample.com app ---//

async fetchFromServer() {
    // return promise..
}

function App() {
    const [sampleState, setSampleState] = React.useState(null)

    React.useEffect(() => {
        fetchFromServer().then((data) => {
            setSampleState(data)
        })
    }, [])

  return (
    <p>{JSON.stringify(sampleState)}</p>
  );
}

//--- android app ---//

public class SampleWebActivity extends Activity {
    SamleWebInterface mWebInterface;
    WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mWebView = new WebView(this);
        setContentView(mWebView);
    
        mWebInterface = new SamleWebInterface();
        mWebView.addJavascriptInterface(mWebInterface, "Native");
        //...
        mWebView.loadUrl("https://sample.com");
    }
}

// Somewhere in another activity
private void showWebScreen() {
    Intent intent = new Intent(this, SampleWebActivity.class);
    // use existing activity if present
    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    startActivity(intent);
}

//--- Question ---//

How can I re-fetch sampleState from server every time SampleWebActivity is shown without reloading the whole page? I want to aviod reloading because the actual web app is much bigger than the sample. Also I don't know the exact state of the web app so it's not clear which url to load. I want to show whetever whas shown before the activity was switched but with updated data.

I'm aware of WebView.evaluateJavascript() but don't know how to interact with the react app after it's compiled into vanilla js.

Upvotes: 0

Views: 1167

Answers (1)

bm_i
bm_i

Reputation: 598

Using the Webview (browser) itself:

You could just use the webview's built in event system, i.e. When the webview returns from being backgrounded for instance you can leverage the document.visibilityState API (https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState):

async fetchFromServer() {
  // return promise..
}

function App() {
  const [sampleState, setSampleState] = React.useState(null)

  React.useEffect(() => {
      const fetchData = () => {
        if (document.visibilityState !== "hidden") {
          fetchFromServer().then((data) => {
              setSampleState(data)
          })
        }
      }
      fetchData();
      document.addEventListener("visibilitychange", fetchData);
      return () => document.removeEventListener("visibilitychange", fetchData);
  }, [])

return (
  <p>{JSON.stringify(sampleState)}</p>
);
}

Injecting/Calling from Java:

async fetchFromServer() {
  // return promise..
}
  
function App() {
  const [sampleState, setSampleState] = React.useState(null)

  React.useEffect(() => {
      const fetchData = () => {
        fetchFromServer().then((data) => {
            setSampleState(data)
        })
      }
      /**
       * Make some globals
       */
      window.__triggerRefetch__ = fetchData;
      window.__setState__ = setSampleState;
      fetchData();
      return () => {
        /**
         * Remove the globals
         */
        delete window.__triggerRefetch__;
        delete window.__setState__;
      }
  }, [])

  return (
    <p>{JSON.stringify(sampleState)}</p>
  );
}

You trigger a refetch with WebView.evaluateJavascript("window.__triggerRefetch__()") or you can inject data with something like WebView.evaluateJavascript("window.__setState__({foo: "bar"})")

Upvotes: 1

Related Questions