From bbd59051cd76d324a71159ecf7d1ffabffd434b5 Mon Sep 17 00:00:00 2001 From: Tal Jacobson Date: Tue, 2 Sep 2025 19:20:51 +0300 Subject: [PATCH 1/3] Refactor Gradle build files - fix example not building with flutter 3.20+ --- example/android/app/build.gradle | 37 ++++++------------- .../EmbeddingV1Activity.java | 2 +- example/android/build.gradle | 16 -------- example/android/settings.gradle | 32 ++++++++++++---- 4 files changed, 36 insertions(+), 51 deletions(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index f3685d9..7caba83 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,37 +1,26 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'dev.flutter.flutter-gradle-plugin' +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } + localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') ?: '1' +def flutterVersionName = localProperties.getProperty('flutter.versionName') ?: '1.0' android { - compileSdk = 35 + compileSdk = 36 namespace 'com.dataxad.flutter_mailer_example' defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.dataxad.flutter_mailer_example" - minSdkVersion flutter.minSdkVersion + minSdkVersion flutter.minSdkVersion targetSdkVersion 35 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -47,10 +36,6 @@ android { } } -flutter { - source '../..' -} - dependencies { testImplementation 'junit:junit:4.12' diff --git a/example/android/app/src/main/java/com/dataxad/flutter_mailer_example/EmbeddingV1Activity.java b/example/android/app/src/main/java/com/dataxad/flutter_mailer_example/EmbeddingV1Activity.java index c0fb07a..1736b98 100644 --- a/example/android/app/src/main/java/com/dataxad/flutter_mailer_example/EmbeddingV1Activity.java +++ b/example/android/app/src/main/java/com/dataxad/flutter_mailer_example/EmbeddingV1Activity.java @@ -5,7 +5,7 @@ // import dev.flutter.plugins.integration_test.IntegrationTestPlugin; // import io.flutter.plugins.imagepicker.ImagePickerPlugin; // import io.flutter.plugins.pathprovider.PathProviderPlugin; -import io.flutter.app.FlutterActivity; +import io.flutter.embedding.android.FlutterActivity; public class EmbeddingV1Activity extends FlutterActivity { // @Override diff --git a/example/android/build.gradle b/example/android/build.gradle index 6b8449d..bc157bd 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,19 +1,3 @@ -buildscript { - ext { - agp_version = '8.7.0' - kotlin_version = '2.1.0' - } - repositories { - google() - mavenCentral() - } - - dependencies { - classpath "com.android.tools.build:gradle:$agp_version" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 44e62bc..cb71091 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,11 +1,27 @@ -include ':app' +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + def localPropertiesFile = new File(rootProject.projectDir, "local.properties") + def properties = new Properties() -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + assert localPropertiesFile.exists() + localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null : "flutter.sdk not set in local.properties" + + // Make the Flutter Gradle plugin available to this build without applying it imperatively. + includeBuild("${flutterSdkPath}/packages/flutter_tools/gradle") +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.7.0" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false +} + +include ":app" From 3779095e1740063df55b70044475d9338c0261fa Mon Sep 17 00:00:00 2001 From: Tal Jacobson Date: Tue, 2 Sep 2025 19:25:02 +0300 Subject: [PATCH 2/3] =?UTF-8?q?android:=20fix=20false=20=E2=80=9Cno=20emai?= =?UTF-8?q?l=20Managers=20available=E2=80=9D=20on=20Android=2011+=20(no-at?= =?UTF-8?q?tachment=20SENDTO)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Symptom: Fresh install, send mail with subject/body and no attachment shows “no email Managers available” (Pixel 8 Pro / Android 16). Works with attachments. Choosing “Always” for a mail app masks the issue; “Only once” keeps failing. - Root cause: Pre-querying PackageManager for ACTION_SENDTO (mailto:) is blocked by Android 11+ package visibility unless declared in or a default app exists, so queries return empty even when handlers are available. With attachments, ACTION_SEND remains discoverable. - Fix: Remove PackageManager pre-query/resolve for SENDTO and start the implicit intent directly (startActivityForResult), catching ActivityNotFoundException to report real absence only. Preserves chooser UX and default behavior (“Only once”/“Always”). Keep appSchema via setPackage and attachment flow with FLAG_GRANT_READ_URI_PERMISSION unchanged. --- .../flutter_mailer/MethodCallHandlerImpl.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/com/dataxad/flutter_mailer/MethodCallHandlerImpl.java b/android/src/main/java/com/dataxad/flutter_mailer/MethodCallHandlerImpl.java index d81798d..96a81a0 100644 --- a/android/src/main/java/com/dataxad/flutter_mailer/MethodCallHandlerImpl.java +++ b/android/src/main/java/com/dataxad/flutter_mailer/MethodCallHandlerImpl.java @@ -4,8 +4,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.ActivityNotFoundException; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; @@ -70,7 +70,12 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result mResult = result; try { final Intent intent = mail(call); - activity.startActivityForResult(intent, MAIL_ACTIVITY_REQUEST_CODE); + try { + activity.startActivityForResult(intent, MAIL_ACTIVITY_REQUEST_CODE); + } catch (ActivityNotFoundException e) { + result.error("not_available", "no email Managers available", null); + mResult = null; + } } catch (FlutterMailerException e) { result.error(e.errorCode, e.errorMessage, e.errorDetails); mResult = null; @@ -164,20 +169,13 @@ private Intent mail(MethodCall options) throws FlutterMailerException { } } - PackageManager manager = context.getPackageManager(); - List list = manager.queryIntentActivities(intent, 0); - - if (list == null || list.size() == 0) { - Log.e(TAG, "size is null or Zero"); - throw new FlutterMailerException("not_available", "no email Managers available", null); - } - - if (list.size() == 1) { - return intent; - } else if (options.hasArgument(APP_SCHEMA) && options.argument(APP_SCHEMA) != null && isAppInstalled((String) options.argument(APP_SCHEMA))) { + // If a specific package schema is requested, set it directly and let the system + // resolve it; avoid pre-querying PackageManager to keep compatibility with + // Android 11+ package visibility restrictions. + if (options.hasArgument(APP_SCHEMA) && options.argument(APP_SCHEMA) != null) { intent.setPackage((String) options.argument(APP_SCHEMA)); - return intent; } + return intent; } From d97351b04c1253946cd82070e4c5f9edbb97cd49 Mon Sep 17 00:00:00 2001 From: Tal Jacobson Date: Tue, 2 Sep 2025 19:30:08 +0300 Subject: [PATCH 3/3] chore: bump version to 3.0.2 and update changelog with Android fixes and example migration --- CHANGELOG.md | 6 ++++++ pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 636af59..e5b4c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 3.0.2 + [Android] Fix false "no email Managers available" when sending without attachments on Android 11+ by removing + PackageManager pre-query for ACTION_SENDTO and launching intent directly + [Example] Migrate Android build to Flutter's declarative Gradle plugin (dev.flutter.flutter-plugin-loader / + dev.flutter.flutter-gradle-plugin), update to Android compileSdk 36, and migrate embedding to v2. + ### 3.0.1 [root] add analysis options [test] remove usage of deprecated `setMockMethodCallHandler` in tests diff --git a/pubspec.yaml b/pubspec.yaml index 4b8a0ed..108d721 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_mailer description: Share an email to device Email - Client supports multiple Attachments -version: 3.0.1 +version: 3.0.2 homepage: https://github.com/taljacobson/flutter_mailer dependencies: