skip to Main Content

I am trying to show my app in share sheet of android and I was able to successfully do it but I am not able to send data from native side to dart using EventChannel.

I have updated my MainActivity to following

class MainActivity: FlutterActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Log.i("TAG123","onCreate")
        onSharedIntent()
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        Log.i("TAG123","configure flutter engine")


    }

    private fun onSharedIntent() {
        val receivedAction: String? = intent.action
        val receivedType: String? = intent.type
        if (receivedAction == Intent.ACTION_SEND) {

            // check mime type
            if (receivedType?.startsWith("text/") == true) {
                val receivedText: String? = intent.getStringExtra(Intent.EXTRA_TEXT)
                if (receivedText != null) {
                    //do your stuff
                    Log.e("TAG123", receivedText.toString())
                    if(flutterEngine?.dartExecutor?.binaryMessenger != null){
                        Log.i("TAG123","flutter engine not null")
                    }
                    Log.e("TAG123", "here")
                    EventChannel(
                        flutterEngine!!.dartExecutor.binaryMessenger,
                        "sharePlatform"
                    ).setStreamHandler(object : EventChannel.StreamHandler {

                        override fun onListen(arguments: Any, events: EventSink) {
                            Log.e("TAG123", "here123")
                            events.success(receivedText)
                        }

                        override fun onCancel(arguments: Any) {
                            Log.e("TAG123", "here123456")
                        }
                    })
                } else {
                    Log.e("TAG123", "no data")
                }
            } else if (receivedType?.startsWith("image/") == true) {
//                val receiveUri: Uri? = intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri?

                val receiveUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
                } else {
                    intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri?
                }

                if (receiveUri != null) {
                    Log.e("TAG123", receiveUri.toString())
                    if(flutterEngine?.dartExecutor?.binaryMessenger != null){
                        Log.i("TAG123","flutter engine not null")
                    }
                    EventChannel(
                        flutterEngine!!.dartExecutor.binaryMessenger,
                        "sharePlatform"
                    ).setStreamHandler(object : EventChannel.StreamHandler {

                        override fun onListen(arguments: Any, events: EventSink) {
                            Log.e("TAG123", "here123")
                            events.success(receiveUri)
                        }

                        override fun onCancel(arguments: Any) {
                            Log.e("TAG123", "here123456")
                        }
                    })
                } else {
                    Log.e("TAG123", "no image data")
                }
            }
        } else if (receivedAction == Intent.ACTION_MAIN) {
            Log.e("TAG123", "onSharedIntent: nothing shared")
        }
    }

}

I have made the required changes to AndroidManifest as well

<intent-filter>
                <action android:name="android.intent.action.SEND" />

                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/*" />
                <data android:mimeType="text/*" />
            </intent-filter>

I can see the url or uri of image when I share it from some other app to my app in logs but EventChannel never works

Below is my dart code

class _MyHomePageState extends State<MyHomePage> {
  var data = "";
  final _eventChannel = const EventChannel('sharePlatform');

  @override
  void initState() {
    super.initState();

    _eventChannel.receiveBroadcastStream().distinct().map((dynamic event) {
      debugPrint("TAG123Flutter $event");
      setState(() {
        data = event;
      });
      // return event;
    });
  }......

4

Answers


  1. This is because you didn’t subscribe to the stream. You are operating on the stream only at the moment MyHomePage is initialized. If you’re not familiar with the topic, I suggest studying event driven programming more, it’s confusing in Dart to read write visualize it.

    StreamSubscription<dynamic>? _eventSubscription;
    
      @override
      void initState() {
        super.initState();
    
        _eventSubscription = _eventChannel.receiveBroadcastStream().listen((dynamic event) {
          debugPrint("TAG123Flutter $event");
          setState(() {
            data = event;
          });
        });
    
      }
    
      @override
      void dispose() {
        _eventSubscription?.cancel(); // Cancel the event subscription when the widget is disposed
        super.dispose();
      }
    

    This way the widget will listen to events that come as long as it is alive.

    If you want to use distinct, you can use a StreamTransformer. For example,

    StreamTransformer<String, String> distinctTransformer =
        StreamTransformer<String, String>.fromHandlers(
      handleData: (String data, EventSink<String> sink) {
        Set<String> uniqueItems = Set<String>();
        if (!uniqueItems.contains(data)) {
          uniqueItems.add(data);
          sink.add(data);
        }
      },
    );
    
    StreamSubscription<String> _streamSubscription;
    _streamSubscription = _streamController.stream
        .transform(distinctTransformer)
        .listen((data) {
          print('Received distinct data: $data');
        });
    
    Login or Signup to reply.
  2. I think the reason is because of

    EventChannel(flutterEngine!!.dartExecutor.binaryMessenger, "sharePlatform").setStreamHandle
    

    Why do you need to use flutterEngine!!.dartExecutor.binaryMessenger?

    in Flutter you create EventChannel like this EventChannel('sharePlatform')

    So I think in ADR code you should use the default executor as messager
    like this: EventChannel(flutterEngine!!.dartExecutor, "sharePlatform")

    Hope it helps.

    Login or Signup to reply.
  3. You are calling onSharedIntent method inside onCreate method directly.
    Looks like that can be the issue because onSharedIntent won’t be invoked in this case. You should wrap the onSharedIntent inside a Handler like this:

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            Log.i("TAG123","onCreate")
    
            /// Wrap onSharedIntent with this Handler.
            Handler(Looper.getMainLooper()).postDelayed(Runnable {
              onSharedIntent()  
            }, 0)
        }
    

    Try this. This should work.


    Update continued from the comment.

    There doesn’t seem any obvious reason. But you can also try to make the streamHandler another class rather than an object type. Just try it as a hack as you said the problem seems to be in the eventChannel invocation.

    Do this:

    class MyStreamHandler(private val text: String) : EventChannel.StreamHandler{
        override fun onListen(arguments: Any, events: EventSink) {
            Log.e("TAG123", "here123")
            events.success(text)
        }
    
        override fun onCancel(arguments: Any) {
            Log.e("TAG123", "here123456")
        }
    }
    

    Then call:

    EventChannel(flutterEngine!!.dartExecutor.binaryMessenger,
                 "sharePlatform").setStreamHandler(
                                  MyStreamHandler(receivedText))
    
    Login or Signup to reply.
  4. I went through this blog to resolve your issue and came upon with the following solution.

    Replace your MainActivity Code with the following

    class MainActivity: FlutterActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        Log.i("TAG123","onCreate")
    }
    
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        Log.i("TAG123","configure flutter engine")
        EventChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            "sharePlatform"
        ).setStreamHandler(object : EventChannel.StreamHandler {
    
            override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
                Log.e("TAG123", "configure here123")
                Log.e("TAG123", "$intent")
                onSharedIntent(events)
            }
    
            override fun onCancel(arguments: Any?) {
                Log.e("TAG123", "configure here123456")
            }
        })
    }
    
    private fun onSharedIntent(events: EventChannel.EventSink) {
        val receivedAction: String? = intent.action
        val receivedType: String? = intent.type
        if (receivedAction == Intent.ACTION_SEND) {
    
            // check mime type
            if (receivedType?.startsWith("text/") == true) {
                val receivedText: String? = intent.getStringExtra(Intent.EXTRA_TEXT)
                if (receivedText != null) {
                    //do your stuff
                    Log.e("TAG123", receivedText.toString())
                    if(flutterEngine?.dartExecutor?.binaryMessenger != null){
                        Log.i("TAG123","flutter engine not null")
                    }
                    Log.e("TAG123", "here")
                    events.success(receivedText)
                } else {
                    Log.e("TAG123", "no data")
                }
            } else if (receivedType?.startsWith("image/") == true) {
    //                val receiveUri: Uri? = intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri?
    
                val receiveUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
                } else {
                    intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri?
                }
                if (receiveUri != null) {
                    Log.e("TAG123", receiveUri.toString())
                    if(flutterEngine?.dartExecutor?.binaryMessenger != null){
                        Log.i("TAG123","flutter engine not null")
                    }
                    events.success(receiveUri.toString())
                } else {
                    Log.e("TAG123", "no image data")
                }
            }
        } else if (receivedAction == Intent.ACTION_MAIN) {
            Log.e("TAG123", "onSharedIntent: nothing shared")
        }
      }
    
    }
    

    Replace your dart code with the following

      @override
      void initState() {
      super.initState();
      _eventChannel.receiveBroadcastStream().listen((dynamic event) {
        debugPrint("TAG123Flutter $event");
        setState(() {
          data = event;
        });
        // return event;
      });
    }
    

    Hope this helps.
    Thanks 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search