Platform specific code error: MissingPluginException - flutter

I want to send an Notification in Flutter, so I set up my platform specific code (only Android) but I get the following error back:
Unhandled Exception: MissingPluginException(No implementation found for method send_notification on channel reminderChannel)
I already cleaned the project but still not working.
Future to invoke method:
const platform = const MethodChannel("reminderChannel");
Future<void> invokeMethod() async {
try {
//FIXME Missing plugin
int testValue = await platform.invokeMethod("send_notification");
} on PlatformException catch (e) {}
}
invokeMethod();
mainActivity:
private static final String notificationChannel = "reminderChannel";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), notificationChannel).setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall methodCall, Result result) {
if (methodCall.method.equals("send_notification")) {
System.out.print("Android Method called");
result.success(5);
} else {
result.notImplemented();
}
}
}
);
}
I want that the testValue variable in invokeMethod equals 5.
Thanks for helping.

I suspect your channel is deallocated at the end of the method.
So keep a reference to the MethodChannel in your acivity:
private static final String notificationChannel = "reminderChannel";
private MethodChannel mainChannel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
reminderChannel = new MethodChannel(getFlutterView(), notificationChannel)
reminderChannel.setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall methodCall, Result result) {
if (methodCall.method.equals("send_notification")) {
System.out.print("Android Method called");
result.success(5);
} else {
result.notImplemented();
}
}
}
);
}

Related

How to listen a startActivityForResult call when using FlutterPlugin?

I'm developing a Flutter Plugin for Android using Java. When i call the MethodChannel, I need to call another Android Intent. If I was using an native activity, it would be simple since I can call startActivityForResult and implement the method onActivityResult on the same class.
But, when I develop a Flutter Plugin, I can implement FlutterPlugin, MethodCallHandler and ActivityAware interfaces but how can I start a new activity and listen for async result?
Java code:
public class GetnetPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
private MethodChannel channel;
private Context context;
private Activity activity;
#Override
public void onAttachedToEngine(#NonNull FlutterPluginBinding flutterPluginBinding) {
context = flutterPluginBinding.getApplicationContext();
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "com.example/method");
channel.setMethodCallHandler(this);
}
#Override
public void onDetachedFromEngine(#NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
#Override
public void onMethodCall(#NonNull MethodCall call, #NonNull Result result) {
switch (call.method){
case "makePayment":
makePayment();
result.success(true);
return;
default:
result.notImplemented();
return;
}
}
#Override
public void onAttachedToActivity(#NonNull ActivityPluginBinding binding) {
this.activity = binding.getActivity();
}
#Override
public void onDetachedFromActivityForConfigChanges() {
this.activity = null;
}
#Override
public void onReattachedToActivityForConfigChanges(#NonNull ActivityPluginBinding binding) {
this.activity = binding.getActivity();
}
#Override
public void onDetachedFromActivity() {
this.activity = null;
}
//This is the method that is called with main action. It starts a new activity by a new intent, then it should listen for a async result
public void makePayment(){
Bundle bundle = new Bundle();
DecimalFormat df = new DecimalFormat("000000000000");
bundle.putString("amount", df.format(10));
bundle.putString("paymentType", "credit");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("getnet://pagamento/v3/payment"));
intent.putExtras(bundle);
if(intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivityForResult(intent, REQUEST_CODE);
}
}
//This is the method that I need to be called after new activity returns a result
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
channel.invokeMethod("success", data);
}
});
}
}
Flutter side:
class Getnet {
final MethodChannel _channel =
const MethodChannel('com.example/method');
final StreamController _streamController = StreamController.broadcast();
Getnet() {
_channel.setMethodCallHandler((call) async {
final method = call.method;
switch (method) {
case 'success':
_streamController.sink.add({
"status": 1,
"msg": call.arguments,
});
break;
case 'error':
_streamController.sink.add({
'status': 0,
'msg': call.arguments['errorMessage'],
});
break;
}
});
}
void dispose() {
_streamController.close();
}
Stream get stream => _streamController.stream;
Future makePayment() async {
await _channel.invokeMethod('makePayment');
}
}
I just found the answer on Enrico Ori's post at Medium: https://medium.com/theotherdev-s/mastering-flutter-create-a-plugin-e81242b6065
The solution is to make Plugin implements ActivityAware and PluginRegistry.ActivityResultListener, which demands onActivityResult implementation.

How to listen the method channel result

On firebase service, there are two method onNewToken and onMessageReceived, the code I tried to implement to get the new token and remote message from them on android side, then feedback to flutter side. But I have no idea how to listen the method channel when it has a result.
// Service
public class FluttersService extends FirebaseMessagingService {
#Override
public void onNewToken(String token) {
...
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Override
public void onMessageReceived(RemoteMessage message) {
...
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
}
// Plugin
public class FlutterPushPlugin extends BroadcastReceiver
implements MethodCallHandler, NewIntentListener, FlutterPlugin, ActivityAware {
// BroadcastReceiver implement
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
if (action.equals(ACTION_TOKEN)) {
String token = intent.getStringExtra(EXTRA_TOKEN);
methodChannel.invokeMethod("onToken", token);
} else if (action.equals(ACTION_REMOTE_MESSAGE)) {
RemoteMessage message =
intent.getParcelableExtra(EXTRA_REMOTE_MESSAGE);
if (message == null) return;
Map<String, Object> content = remoteMessageToMap(message);
methodChannel.invokeMethod("onMessage", content);
}
}
#Override
public void onMethodCall(final MethodCall call, #NonNull final Result result) {
switch (call.method) {
case "onToken":
// How to response the result to flutter side?
break;
case "onMessage":
// How to response the result to flutter side?
break;
default:
result.notImplemented();
return;
}
}
}
Use Event channel for sending an event to flutter from native.
A complete description is provided in the below article.
https://rvsevtag62.medium.com/event-channel-to-listen-to-broadcast-events-from-android-43a813672896

startup.ActivityLogin has leaked window DecorView#3a9e526[ActivityLogin] that was originally added here

Here is my code, I am trying to allow the user to sign in via his Gmail id. But I am getting this error:
Error Image
Not sure what I am missing, I think I have called dismiss() at the right place. Is it the timing issue?
The app is launching fine in my phone though. I am not sure if it will crash in other devices so I want to get rid of this error.
//Google Sign In
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GOOGLE_SIGN_IN_KEY) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
firebaseAuthWithGoogle(account);
} catch (ApiException e) {
if (e.getStatusCode() == 12500) {
Snackbar.make(findViewById(android.R.id.content), "Sign In Error! Update Google Play Service.", Snackbar.LENGTH_LONG).show();
}
}
}
}
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = firebaseAuth.getCurrentUser();
showGoogleSignUpDialog();
storeUserInfo(user.getPhotoUrl().toString(), user.getUid(), user.getDisplayName(), user.getEmail());
} else {
Snackbar.make(findViewById(android.R.id.content), "Sign In Failed!", Snackbar.LENGTH_LONG).show();
}
}
});
}
private void storeUserInfo(final String stringUserImage, final String stringUserID, final String stringName, final String stringEmail) {
FirebaseUser user = firebaseAuth.getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(stringName)
.setPhotoUri(Uri.parse(stringUserImage))
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
firebaseFirestore.collection("UserData").document(stringUserID).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.getData() != null && documentSnapshot.getData().size() > 0) {
Snackbar.make(findViewById(android.R.id.content), "Welcome back!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class));
finish();
} else {
createUserData(stringUserID, stringUserImage, stringName, stringEmail);
}
}
});
}
}
});
}
private void createUserData(String stringUserID, String stringUserImage, String stringName, String stringEmail) {
final Map<String, Object> userDataMap = new HashMap<>();
userDataMap.put("userName", stringName);
userDataMap.put("userImage", stringUserImage);
userDataMap.put("userID", stringUserID);
userDataMap.put("userPoints", 100);
userDataMap.put("userVerified", true);
userDataMap.put("userEmail", stringEmail);
userDataMap.put("timestamp", FieldValue.serverTimestamp());
firebaseFirestore.collection("UserData").document(stringUserID).set(userDataMap)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
alertGoogleSignIn.dismiss();
Snackbar.make(findViewById(android.R.id.content), "Welcome!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class).putExtra("canShowCoinCredit", true));
finish();
}
}, 3000);
}
});
}
private void showGoogleSignUpDialog() {
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Signing in");
alert.setMessage("Please hold on while we process...");
alert.setCancelable(false);
alertGoogleSignIn = alert.create();
alertGoogleSignIn.show();
}
Try the following:
Generate the onStop() override method and transfer your startactivity as shown below. The finish() method you have already specified will invoke the onStop() override method then your activity should be started.
#Override
protected void onStop() {
super.onStop();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class).putExtra ("canShowCoinCredit", true));
}
This error occurred because alertGoogleSignIn dialog is not dismissed before intent to next screen
Need to dismiss alertGoogleSignIn before startIntent
Please add alertGoogleSignIn.dismiss() in following function
private void storeUserInfo(final String stringUserImage, final String stringUserID, final String stringName, final String stringEmail) {
FirebaseUser user = firebaseAuth.getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(stringName)
.setPhotoUri(Uri.parse(stringUserImage))
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
firebaseFirestore.collection("UserData").document(stringUserID).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
alertGoogleSignIn.dismiss(); // dismiss dialog here
if (documentSnapshot.getData() != null && documentSnapshot.getData().size() > 0) {
Snackbar.make(findViewById(android.R.id.content), "Welcome back!", Snackbar.LENGTH_LONG).show();
startActivity(new Intent(ActivityLogin.this, ActivityHome.class));
finish();
} else {
createUserData(stringUserID, stringUserImage, stringName, stringEmail);
}
}
});
}
}
});
}
I hope this helps you

No implementation found for method listen on channel for ConnectionStatus library

I'm trying to use FlutterCheckInternetConnectivity on our application, after run application i get this error:
plugins.flutter.io/connectivity_status:
MissingPluginException(No implementation found for method listen on channel
plugins.flutter.io/connectivity_status)
on this part of code:
void dispose() {
connectionChangeController.close();
}
ConnectionStatusSingleton class:
class ConnectionStatusSingleton {
static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
ConnectionStatusSingleton._internal();
static ConnectionStatusSingleton getInstance() => _singleton;
bool hasConnection = false;
StreamController connectionChangeController = new StreamController.broadcast();
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
checkConnection();
}
Stream get connectionChange => connectionChangeController.stream;
void dispose() {
connectionChangeController.close();
}
void _connectionChange(ConnectivityResult result) {
checkConnection();
}
Future<bool> checkConnection() async {
bool previousConnection = hasConnection;
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
hasConnection = true;
} else {
hasConnection = false;
}
} on SocketException catch(_) {
hasConnection = false;
}
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
my implemented this library:
main() {
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
connectionStatus.initialize();
runApp(MaterialApp(
...
));
}
_FragmentPostsState widget class:
class _FragmentPostsState extends State<FragmentPosts> {
StreamSubscription _connectionChangeStream;
bool isOffline = false;
#override
void initState() {
super.initState();
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
_connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
}
#override
Widget build(BuildContext context) {
return (isOffline)
? Center(...)
: PostPage();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
print('connection changed ...');
isOffline = !hasConnection;
});
}
}
I had this same problem and eventually I restarted the app from command-line and this solved the problem.

FirebaseImageLoader doesn't download image

I'm trying to download image from storage inside of ViewHolder, but it doesn't work:
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReference();
StorageReference imgRef = storageReference.child("11325404_436219506581300_875224883_a.jpg");
Glide.with(context)
.using(new FirebaseImageLoader())
.load(imgRef)
.into(imageView);
When I use uri instead of FirebaseImageLoader everything works fine:
Glide.with(context)
.load(uri)
.centerCrop()
.into(imageView)
What could be a reason for that?
Update: I've tried to add this code and it shows me right links to images in storage
storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Log.v(TAG, String.valueOf(uri));
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});