shawnXiao
shawnXiao

Reputation: 880

React Native onActivityResult not work

I have a webview component of React Native. The webview should support input type is file, so I do it as:

File Upload in WebView

and the webview implements ActivityEventListener and override onActivityResult.But the onActivityResult not working.

The Code is

class RNWebView extends WebView implements ActivityEventListener {
      protected class GeoWebChromeClient extends WebChromeClient {
          public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
           ...
            mActivity.startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
            return true;
          }
      }

    public RNWebView(ReactContext reactContext, Activity activity) {
        super(reactContext);
        // Add the listener for `onActivityResult`
        reactContext.addActivityEventListener(this);
        ...
     }

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
    // Your logic here
    Log.d("Tanck", "requestCode:" + requestCode + "----" + "resultCode:" + resultCode);
}

}

Upvotes: 6

Views: 9025

Answers (3)

Somnath Kadam
Somnath Kadam

Reputation: 6357

If any one using kotlin with react-native module with Promise, plesae refer below code,

import android.app.Activity
import android.content.Intent
import android.util.Log
import com.facebook.react.bridge.*
import com.onboardinglib.HostActivity

class ConsistyOnboarding (reactContext: ReactApplicationContext) :
  ReactContextBaseJavaModule(reactContext) {

  private val CODE = 999
  private var promise: Promise? = null
  private val reContext: ReactApplicationContext? = reactContext

  fun dumpIntent(intent: Intent) {
    LogPrint("Bundle data", "Dumping intent start")

    val bundleData = intent.extras
    if (bundleData != null) {
      for (key in bundleData.keySet()) {
        LogPrint(
          "Bundle data-->",
          key + " : " + if (bundleData[key] != null) bundleData[key] else "NULL"
        )
      }
    }
  }

  override fun getName(): String {
    return "ConsistyOnboarding"
  }

  private val mActivityEventListener: ActivityEventListener =
    object : BaseActivityEventListener() {
      override fun onActivityResult(
        activity: Activity,
        requestCode: Int,
        resultCode: Int,
        data: Intent
      ) {
        LogPrint("mActivityEventListener", "Started")

        if (data == null) {
          resolve("01", "No action taken", "0")
          return
        }

        dumpIntent(data)

        if (resultCode == Activity.RESULT_OK) {
          try {
            val status = data.getBooleanExtra("status", false)
            val response = data.getIntExtra("response", 0)
            val message = data.getStringExtra("message")
            resolve(status.toString(), response.toString(), message.toString())
            return
          } catch (e: Exception) {
            e.printStackTrace()
            resolve("01", "Exception occurred in on-boarding " + e.message, "0")
          }
        }
        resolve("01", "No action taken", "0")
      }
    }


  init {
    reContext?.addActivityEventListener(mActivityEventListener)
  }


  @ReactMethod
  fun Onboarding(
    partnerId: String, partnerKey: String  prm: Promise
  ) {

    promise = prm
    val currentActivity = currentActivity
    val intent = Intent(currentActivity, HostActivity::class.java)

    intent.putExtra("pId", partnerId) 
    intent.putExtra("ApiKey", partnerKey) 
    
    try {
      currentActivity?.startActivityForResult(intent, CODE)
    } catch (e: Exception) {
      e.printStackTrace()
      resolve("01", "No action taken", "0")
    }
  }

  private fun resolve(
    statusCode: String,
    response: String,
    message: String
  ) {
    if (promise == null) {
      return
    }

    val map = Arguments.createMap()

    map.putString("statusCode", statusCode)
    map.putString("response", response)
    map.putString("message", message)

    promise!!.resolve(map)
    promise = null
  }

  private fun LogPrint(key: String?, value: String?) {
    if (key == null || value == null) {
      return
    }
    Log.i(key, value)
  }
}

Main part is need to add event Listener,

init {
    reContext?.addActivityEventListener(mActivityEventListener)
  }

Upvotes: 1

f4z3k4s
f4z3k4s

Reputation: 1241

To make the solution complete:

in your MainActivity (or in the Activity, where RN is initialized and mReactInstanceManager is used if it is a part of a native app):

...
private ReactInstanceManager mReactInstanceManager;
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
}

in your Module:

public class MyModule extends ReactContextBaseJavaModule implements ActivityEventListener {
    static final int REQUEST_VIDEO_CAPTURE = 1;

    final ReactApplicationContext reactContext;
    Promise promise;

    public GeneralIntentModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        this.reactContext.addActivityEventListener(this);
    }

    @Override
    public String getName() {
        return "MyModule ";
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        this.promise.resolve(data.getDataString());
    }
}

Upvotes: 1

oscarthecat
oscarthecat

Reputation: 1841

Maybe late hope it helps.

native module's onActivityResult is called by ReactContext which is called by ReactInstanceManagerImpl which in 0.29 is called by ReactActivity. In the example above MyWb extends Activity not ReactActivity, so ReactInstanceManagerImpl is never called.

The solution is just in your activity's onActivityResult call ReactInstanceManager's onActivityResult since you already have your own ReactInstanceManager object reference.

The Activity you are launching React Native from should have an override like this:

// Manually pass along the `onActivityResult` event to React Native event listeners.
// We are not extending from `ReactActivity` so we need to do this manually.
// 
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

  mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data );

}

Upvotes: 18

Related Questions