Reputation: 57
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;
});
}......
Upvotes: 1
Views: 1043
Reputation: 1911
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 :)
Upvotes: 1
Reputation: 54
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))
Upvotes: 0
Reputation: 3054
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.
Upvotes: 0
Reputation: 730
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');
});
Upvotes: 0