darwin-morocho / flutter-facebook-auth

A flutter plugin to add login with facebook in your flutter app
197 stars 142 forks source link

Facebook login flow is not working anymore after migration my flutter project to flutterEmbedding v2 #44

Closed gsiewe closed 3 years ago

gsiewe commented 3 years ago

Describe the bug The facebook login flow used to work properly, but since i migrated to flutterEmbedding v2 it is now working anymore on android. on iOS it works though. This call await FacebookAuth.instance.login() never returns.

Environment Add your flutter doctor -v [✓] Flutter (Channel stable, 1.22.5, on Mac OS X 10.15.5 19F101 darwin-x64, locale de-DE) • Flutter version 1.22.5 at /Users/gsiewe/workspace/private/flutter • Framework revision 7891006299 (7 weeks ago), 2020-12-10 11:54:40 -0800 • Engine revision ae90085a84 • Dart version 2.10.4

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0) • Android SDK at /Users/gsiewe/Library/Android/sdk • Platform android-30, build-tools 30.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.3) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 12.3, Build version 12C33 • CocoaPods version 1.9.3

[✓] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 48.1.2 • Dart plugin version 193.7547 • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[!] IntelliJ IDEA Ultimate Edition (version 2020.1.2) • IntelliJ at /Applications/IntelliJ IDEA.app ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • For information about installing plugins, see https://flutter.dev/intellij-setup/#installing-the-plugins

[✓] Connected device (2 available) • sdk gphone x86 (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator) • iPhone 12 Pro Max (mobile) • 56B67681-CBCA-4927-BAC6-7DD550E80343 • ios • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)

! Doctor found issues in 1 category.

Add your pubspec.yaml name: chatetyamo description: Chat&Yamo application de rencontre pour les jeunes Camerounais.

dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter

http: "^0.12.2" shared_preferences: "^0.5.12" flutter_cache_manager: "^1.4.2" web_socket_channel: "^1.1.0" event_bus: "^1.1.1" flutter_webview_plugin: "^0.3.11" in_app_purchase: ^0.3.3+1 firebase_messaging: "^6.0.16" material_design_icons_flutter: "4.0.5655" fluttertoast: "^7.1.1" flutter_slidable: "^0.5.7" flutter_facebook_auth: ^2.0.0+1 share: "^0.6.5+2" firebase_performance: ^0.3.1+4 rxdart: ^0.24.1 url_launcher: ^5.7.2 rflutter_alert: ^1.1.0 flutter_custom_tabs: ^0.6.0 geolocator: ^5.3.2+2 image_crop: ^0.3.3 intro_slider: ^2.3.3 highlighter_coachmark: "^0.0.3" rate_my_app: "^0.4.0" photo_view: ^0.10.2 zoomable_image: ^1.3.1 timer_builder: "^1.3.0" package_info: ^0.4.3 flutter_screenutil: ^3.1.1 super_tooltip: ^0.9.0 currency_pickers: ^1.0.6 backdrop: ^0.4.6 flutter_native_splash: ^0.1.9 quiver: ^2.1.3 apple_sign_in: ^0.1.0 flushbar: ^1.10.4 intl: ^0.16.1 image_picker: ^0.6.7+14 expandable_text: ^1.1.0

dev_dependencies: flutter_test: sdk: flutter flutter_launcher_icons: "^0.7.4"

flutter_icons: android: true ios: true image_path: "assets/new_logo.png" image_path_android: "assets/new_logo.png" image_path_ios: "assets/new_logo.png"

flutter: uses-material-design: true assets:

flutter_native_splash: image: assets/background.png color: "42a5f5" fill: true android_disable_fullscreen: false ios: false

Add your AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.chatetyamo">

<!-- The INTERNET permission is required for development. Specifically,
     flutter needs it to communicate with the running application
     to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- io.flutter.app.FlutterApplication is an android.app.Application that
     calls FlutterMain.startInitialization(this); in its onCreate method.
     In most cases you can leave this as-is, but you if you want to provide
     additional functionality it is fine to subclass or reimplement
     FlutterApplication and put your custom class here. -->
<application
    android:name="com.chatetyamo.Application"
    android:label="Chat&amp;Yamo"
    android:icon="@mipmap/ic_launcher">

    <meta-data
        android:name="flutterEmbedding"
        android:value="2" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@mipmap/ic_launcher" />

    <activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">
        <!-- This keeps the window background of the activity showing
             until Flutter renders its first frame. It can be removed if
             there is no splash screen (such as the default splash screen
             defined in @style/LaunchTheme). -->
        <meta-data
            android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
            android:value="true" />
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
        <intent-filter>
            <action android:name="FLUTTER_NOTIFICATION_CLICK" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
    <activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

    <meta-data android:name="com.facebook.sdk.ApplicationId"
        android:value="@string/facebook_app_id"/>

    <!-- meta-data android:name="firebase_performance_logcat_enabled" android:value="true" /-->
    <!-- meta-data android:name="firebase_performance_collection_enabled" android:value="false" /-->

    <activity android:name="com.facebook.FacebookActivity"
        android:configChanges=
            "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
        android:label="@string/app_name" />

    <activity
        android:name="com.facebook.CustomTabActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="@string/fb_login_protocol_scheme" />
        </intent-filter>
    </activity>

</application>

Add your /app/res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>

Chat&Yamo FacebookAppID fbFacebookAppID

To Reproduce

Expected behavior I expect the call await FacebookAuth.instance.login() to terminate either with an error or with a valid access token

darwin-morocho commented 3 years ago

@gsiewe please open the android folder on Android Studio and run the project. Now check if you have an error in your logcat.

I think that your migration is not correctly because this plugin works perfect in flutter: ">=1.12.13+hotfix.6 <2.0.0"

gsiewe commented 3 years ago

@darwin-morocho, i followed your instructions and i opened and executed the project from the android folder. I can't see any error in the logs. The logs are the same when i run the project normally.

Here the logs i see when starting the login flow:

I/behavior::: DIALOG_ONLY
I/WebViewFactory: Loading com.google.android.webview version 83.0.4103.44 (code 410404481)
I/com.chatetyamo: The ClassLoaderContext is a special shared library.
I/com.chatetyamo: The ClassLoaderContext is a special shared library.
I/cr_LibraryLoader: Loaded native library version number "83.0.4103.44"
I/cr_CachingUmaRecorder: Flushed 3 samples from 3 histograms.
D/TransportRuntime.SQLiteEventStore: Storing event with priority=DEFAULT, name=FIREPERF for destination cct
D/TransportRuntime.JobInfoScheduler: Upload for context TransportContext(cct, DEFAULT, MSRodHRwczovL2ZpcmViYXNlbG9nZ2luZy1wYS5nb29nbGVhcGlzLmNvbS92MS9maXJlbG9nL2xlZ2FjeS9iYXRjaGxvZ1xBSXphU3lDY2traUg4aTJaQVJ3T3MxTEV6RktsZDE1YU9HOG96S28=) is already scheduled. Returning...
D/TransportRuntime.SQLiteEventStore: Storing event with priority=DEFAULT, name=FIREPERF for destination cct
D/TransportRuntime.JobInfoScheduler: Upload for context TransportContext(cct, DEFAULT, MSRodHRwczovL2ZpcmViYXNlbG9nZ2luZy1wYS5nb29nbGVhcGlzLmNvbS92MS9maXJlbG9nL2xlZ2FjeS9iYXRjaGxvZ1xBSXphU3lDY2traUg4aTJaQVJ3T3MxTEV6RktsZDE1YU9HOG96S28=) is already scheduled. Returning...
D/TransportRuntime.SQLiteEventStore: Storing event with priority=DEFAULT, name=FIREPERF for destination cct
D/TransportRuntime.JobInfoScheduler: Upload for context TransportContext(cct, DEFAULT, MSRodHRwczovL2ZpcmViYXNlbG9nZ2luZy1wYS5nb29nbGVhcGlzLmNvbS92MS9maXJlbG9nL2xlZ2FjeS9iYXRjaGxvZ1xBSXphU3lDY2traUg4aTJaQVJ3T3MxTEV6RktsZDE1YU9HOG96S28=) is already scheduled. Returning...
gsiewe commented 3 years ago

here is my MainActivity class after the migration:

package com.chatetyamo;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import android.telephony.TelephonyManager;

import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {

  public static final String CHANNEL = "com.chatetyamo/image_picker";
  public static final String CHANNEL_CONNECTIVITY_MANAGER = "com.chatetyamo/bandwidth_connectivity_manager";
  public MethodChannel.Result result = null;
  public static final int REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY = 2342;
  public static final int REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION = 2344;

  static
  {
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
      AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
      case REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY:
        if (resultCode == Activity.RESULT_OK && data != null) {
          String path = new FileUtils().getPathFromUri(this, data.getData());
          if (result != null) {
            result.success(path);
          }
          this.result = null;
        }
        break;
      default:
    }
  }

  @Override
  public void onRequestPermissionsResult(
          int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    boolean permissionGranted =
            grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;

    switch (requestCode) {
      case REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION:
        if (permissionGranted) {
          doPickImage();
        }
        break;
      default:
        return;
    }

    if (!permissionGranted) {
      if (result != null) {
        result.success(null);
      }
      this.result = null;
    }
  }

  @Override
  public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    super.configureFlutterEngine(flutterEngine);
    final MainActivity activity = this;

    new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL).setMethodCallHandler(
      (call, result) -> {
        if (call.method.equals("pickImage")) {
          activity.chooseImageFromGallery(result);
        }
      });

    new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_CONNECTIVITY_MANAGER).setMethodCallHandler(
      (call, result) -> {
        if (call.method.equals("checkBandwidth")) {
          Context applicationContext = getApplicationContext();
          ConnectivityManager connectivityManager = (ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
          if (connectivityManager != null) {
            NetworkInfo info = connectivityManager.getActiveNetworkInfo();
            if (info != null && info.getType() == ConnectivityManager.TYPE_WIFI) {
              result.success("good");
            }
            else if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE) {
              switch(info.getSubtype()) {
                case TelephonyManager.NETWORK_TYPE_IWLAN:
                  result.success("good");
                  return;
                case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
                  result.success("bad");
                  return;
                case TelephonyManager.NETWORK_TYPE_GSM:
                  result.success("bad");
                  return;
                case TelephonyManager.NETWORK_TYPE_1xRTT:
                  result.success("bad"); // ~ 50-100 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_CDMA:
                  result.success("bad"); // ~ 14-64 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_EDGE:
                  result.success("bad"); // ~ 50-100 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_EVDO_0:
                  result.success("good"); // ~ 400-1000 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_EVDO_A:
                  result.success("good"); // ~ 600-1400 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_GPRS:
                  result.success("bad"); // ~ 100 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_HSDPA:
                  result.success("good"); // ~ 2-14 Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_HSPA:
                  result.success("good"); // ~ 700-1700 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_HSUPA:
                  result.success("good"); // ~ 1-23 Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_UMTS:
                  result.success("good"); // ~ 400-7000 kbps
                  return;
                /*
                 * Above API level 7, make sure to set android:targetSdkVersion
                 * to appropriate level to use these
                 */
                case TelephonyManager.NETWORK_TYPE_EHRPD: // API level 11
                  result.success("good"); // ~ 1-2 Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_EVDO_B: // API level 9
                  result.success("good"); // ~ 5 Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_HSPAP: // API level 13
                  result.success("good"); // ~ 10-20 Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_IDEN: // API level 8
                  result.success("bad"); // ~25 kbps
                  return;
                case TelephonyManager.NETWORK_TYPE_LTE: // API level 11
                  result.success("good"); // ~ 10+ Mbps
                  return;
                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                default:
                  result.success("bad");
              }
            }
            else {
              result.success("bad");
            }
          }
          else {
            result.success("bad");
          }
        }
      });
  }

  private void chooseImageFromGallery(MethodChannel.Result result) {
    this.result = result;

    if (!isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) {
      askForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, REQUEST_EXTERNAL_IMAGE_STORAGE_PERMISSION);
      return;
    }

    doPickImage();
  }

  private void doPickImage() {
    Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
    photoPickerIntent.setType("image/*");

    startActivityForResult(photoPickerIntent, REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY);
  }

  private boolean isPermissionGranted(String permissionName) {
    return ActivityCompat.checkSelfPermission(this, permissionName)
            == PackageManager.PERMISSION_GRANTED;
  }

  private void askForPermission(String permissionName, int requestCode) {
    ActivityCompat.requestPermissions(this, new String[] {permissionName}, requestCode);
  }
}
darwin-morocho commented 3 years ago

onActivityResult

The problem is because you are overriding the onActivityResult method. Just comment your onActivityResult method and check if the login with facebook works.

In the new flutter Android APIs you can't override the onActivityResult method because all plugins that need this method won't work. For example if you use the plugin google_sign_in you will see that it doesn't work because this plugin needs the onActivityResult method.

gsiewe commented 3 years ago

@darwin-morocho, thank you for your help it is working now. i'm still overriding, but i call super like this

@Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
      case REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY:
        if (resultCode == Activity.RESULT_OK && data != null) {
          String path = new FileUtils().getPathFromUri(this, data.getData());
          if (result != null) {
            result.success(path);
          }
          this.result = null;
        }
        break;
      default:
    }
  }