1

I am trying to run paystack inside a webview however it has a button called cancel payment that doesn't do anything. I am told that the button runs a function called onClose that runs window.close but since its in a webview it doesn't work.

Now I am trying to hook into that function and ideally make a navigation action but for now just a console.log or alert would be good enough.

This is what the webview looks like now

<WebView 
      source={{ uri: authorization_url }}
      onNavigationStateChange={() => console.log('navstate changed')}
      cacheEnabled={false}
      cacheMode={'LOAD_NO_CACHE'}
      onMessage={(e) => {
          console.log('pressed')
          JSON.parse(e.nativeEvent?.data);
      }}
      onClose={() => {
        console.log('on close')
        navigation.navigate(callBackRoute)
      }}
    />

I thought of adding injectedJavaScript prop but i cant work out what to put in it, I've tried a bunch of things so far without any success.

Below is link to payfast documentation https://paystack.com/docs/guides/using_the_paystack_checkout_in_a_mobile_webview/

Update: I got this working with a timeout hack, would definitely prefer to find a way to remove the timeout and just make it work correctly but the following code is functional

const js = `
      setTimeout(function() {
      var buttons = document.getElementsByTagName('button')
      buttons.forEach((button) => {
        if(button.innerHTML.includes('Cancel Payment')) {
          button.addEventListener("click", function() {  
              var resp = {event:'cancelled'};
              window.ReactNativeWebView.postMessage(JSON.stringify(resp))
              });
        }
      })
    }, 3000);
      true; // note: this is required, or you'll sometimes get silent failures
    `

and

const onNavigationStateChange = state => {
    const { url } = state;
    webViewRef.current.injectJavaScript(js)
    // other navigationStateChangeCode
  }
Adam Katz
  • 6,999
  • 11
  • 42
  • 74
  • Put in injectedJavaScript script that find a button and add event listener, witch will call onMessage via window.ReactNativeWebView.postMessage() – Quintis Oct 14 '21 at 18:26
  • this is what im trying to do, how do i find the button though? – Adam Katz Oct 14 '21 at 18:48
  • please ,paste here in comments html markup of button – Quintis Oct 14 '21 at 19:15
  • i dont have it but ill add the documentation to the question – Adam Katz Oct 14 '21 at 19:33
  • From docmentation - The workaround is to have your WebView listen for when the URL has been redirected to https://standard.paystack.co/close – Quintis Oct 14 '21 at 19:40
  • to my prev comment https://developer.mozilla.org/ru/docs/Web/API/WindowEventHandlers/onhashchange – Quintis Oct 14 '21 at 19:51
  • unfortuanately that doesnt work, window.close isnt caught by the onNavigationStateChange since its ignored – Adam Katz Oct 14 '21 at 19:53
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/238151/discussion-between-quintis-and-adam-katz). – Quintis Oct 14 '21 at 19:54
  • Did you try to use [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to detect DOM changes? If it supports, you can detect the button when it comes in the DOM. [Somebody tried before but did not succeed.](https://github.com/react-native-webview/react-native-webview/issues/1292) – ridvanaltun Oct 22 '21 at 11:46

1 Answers1

1

You can try using the window.onload event which is fired once the document has finished loading, instead of setting a timeout.

function onButtonClick() {
  var resp = {event:'cancelled'};
  window.ReactNativeWebView.postMessage(JSON.stringify(resp))
}

window.onload = function() {
  var buttons = document.getElementsByTagName('button');
  buttons.forEach((button) => {
    if(button.innerHTML.includes('Cancel Payment')) {
      button.addEventListener("click", onButtonClick);
    }
  })
}
  • didnt work :( The website starts in a loading state so im assuming it has something to do with that. – Adam Katz Oct 17 '21 at 21:26
  • Hello, were you able to resolve this without using setTimeout? – kingsJayson Feb 21 '23 at 00:33
  • The problem with settimeout is what if the page delays for more than the setTimeout. Is there a way to detect when the page is fully loaded with css files and all that? I can see that the page uses loading state and the script fires at this time which fails to find any html element because there was none. The settimeout helps to delay the script from running instantly. This works but what if the page takes longer time to load, let say, longer than 4 seconds. – kingsJayson Feb 21 '23 at 01:21