Repository: ABausG/home_widget

Issue:
Pinning widget
It might be nice to add this feature https://developer.android.com/develop/ui/views/appwidgets/configuration#pin



Fix patch:
diff --git a/README.md b/README.md
index 39648ff5..2995a1da 100644
--- a/README.md
+++ b/README.md
@@ -446,6 +446,23 @@ WorkmanagerPlugin.setPluginRegistrantCallback { registry in
 ```
 to [AppDelegate.swift](example/ios/Runner/AppDelegate.swift)
 
+### Request Pin Widget
+Requests to Pin (Add) the Widget to the users HomeScreen by pinning it to the users HomeScreen.
+
+```dart
+HomeWidget.requestPinWidget(
+    name: 'HomeWidgetExampleProvider',
+    androidName: 'HomeWidgetExampleProvider',
+    qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
+);
+```
+
+This method is only supported on [Android, API 26+](https://developer.android.com/develop/ui/views/appwidgets/configuration#pin).
+If you want to check whether it is supported on current device, use:
+
+```dart
+HomeWidget.isRequestPinWidgetSupported();
+```
 
 ---
 
diff --git a/android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetPlugin.kt b/android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetPlugin.kt
index 4437a7f3..46a00b65 100644
--- a/android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetPlugin.kt
+++ b/android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetPlugin.kt
@@ -3,6 +3,7 @@ package es.antonborri.home_widget
 import android.app.Activity
 import android.appwidget.AppWidgetManager
 import android.content.*
+import android.os.Build
 import androidx.annotation.NonNull
 import io.flutter.embedding.engine.plugins.FlutterPlugin
 import io.flutter.embedding.engine.plugins.activity.ActivityAware
@@ -107,6 +108,37 @@ class HomeWidgetPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
                 saveCallbackHandle(context, dispatcher, callback)
                 return result.success(true)
             }
+            "isRequestPinWidgetSupported" -> {
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+                    return result.success(false)
+                }
+
+                val appWidgetManager = AppWidgetManager.getInstance(context.applicationContext)
+                return result.success(appWidgetManager.isRequestPinAppWidgetSupported)
+            }
+            "requestPinWidget" -> {
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+                    return result.success(null)
+                }
+
+                val qualifiedName = call.argument<String>("qualifiedAndroidName")
+                val className = call.argument<String>("android") ?: call.argument<String>("name")
+
+                try {
+                    val javaClass = Class.forName(qualifiedName ?: "${context.packageName}.${className}")
+                    val myProvider = ComponentName(context, javaClass)
+
+                    val appWidgetManager = AppWidgetManager.getInstance(context.applicationContext)
+
+                    if (appWidgetManager.isRequestPinAppWidgetSupported) {
+                        appWidgetManager.requestPinAppWidget(myProvider, null, null)
+                    }
+
+                    return result.success(null)
+                } catch (classException: ClassNotFoundException) {
+                    result.error("-4", "No Widget found with Name $className. Argument 'name' must be the same as your AppWidgetProvider you wish to update", classException)
+                }
+            }
             else -> {
                 result.notImplemented()
             }
diff --git a/ios/Classes/SwiftHomeWidgetPlugin.swift b/ios/Classes/SwiftHomeWidgetPlugin.swift
index c8afcf4a..33658fdc 100644
--- a/ios/Classes/SwiftHomeWidgetPlugin.swift
+++ b/ios/Classes/SwiftHomeWidgetPlugin.swift
@@ -149,8 +149,12 @@ public class SwiftHomeWidgetPlugin: NSObject, FlutterPlugin, FlutterStreamHandle
               "Interactivity is only available on iOS 17.0",
             details: nil))
       }
-
-    } else {
+    } else if call.method == "isRequestPinWidgetSupported" {
+      result(false)
+    } else if call.method == "requestPinWidget" {
+      result(nil)
+    }
+    else {
       result(FlutterMethodNotImplemented)
     }
   }
diff --git a/lib/home_widget.dart b/lib/home_widget.dart
index 5f606d5c..e84ce925 100644
--- a/lib/home_widget.dart
+++ b/lib/home_widget.dart
@@ -50,6 +50,34 @@ class HomeWidget {
     });
   }
 
+  /// Determines whether pinning HomeScreen Widget is supported.
+  static Future<bool?> isRequestPinWidgetSupported() {
+    return _channel.invokeMethod('isRequestPinWidgetSupported');
+  }
+
+  /// Requests to Pin (Add) the HomeScreenWidget to the User's Home Screen
+  ///
+  /// This is supported only on some Android Launchers and only with Android API 26+
+  ///
+  /// Android Widgets will look for [qualifiedAndroidName] then [androidName] and then for [name]
+  /// There is no iOS alternative.
+  ///
+  /// [qualifiedAndroidName] will use the name as is to find the WidgetProvider.
+  /// [androidName] must match the classname of the WidgetProvider, prefixed by the package name.
+  static Future<void> requestPinWidget({
+    String? name,
+    String? androidName,
+    // String? iOSName,
+    String? qualifiedAndroidName,
+  }) {
+    return _channel.invokeMethod('requestPinWidget', {
+      'name': name,
+      'android': androidName,
+      // 'ios': iOSName,
+      'qualifiedAndroidName': qualifiedAndroidName,
+    });
+  }
+
   /// Returns Data saved with [saveWidgetData]
   /// [id] of Data Saved
   /// [defaultValue] value to use if no data was found


Test patch:
diff --git a/test/home_widget_test.dart b/test/home_widget_test.dart
index 3ad17c2a..d7130c1a 100644
--- a/test/home_widget_test.dart
+++ b/test/home_widget_test.dart
@@ -47,6 +47,10 @@ void main() {
           return Future.value(launchUri);
         case 'registerBackgroundCallback':
           return true;
+        case 'requestPinWidget':
+          return null;
+        case 'isRequestPinWidgetSupported':
+          return true;
       }
     });
   });
@@ -102,6 +106,31 @@ void main() {
     expect(arguments['qualifiedAndroidName'], 'com.example.androidName');
   });
 
+  test('isRequestPinWidgetSupported', () async {
+    expect(
+      await HomeWidget.isRequestPinWidgetSupported(),
+      true,
+    );
+
+    final arguments = await passedArguments.future;
+
+    expect(arguments, isNull);
+  });
+
+  test('requestPinWidget', () async {
+    await HomeWidget.requestPinWidget(
+      name: 'name',
+      androidName: 'androidName',
+      qualifiedAndroidName: 'com.example.androidName',
+    );
+
+    final arguments = await passedArguments.future;
+
+    expect(arguments['name'], 'name');
+    expect(arguments['android'], 'androidName');
+    expect(arguments['qualifiedAndroidName'], 'com.example.androidName');
+  });
+
   group('initiallyLaunchedFromHomeWidget', () {
     test('Valid Uri String gets parsed', () async {
       launchUri = 'homeWidget://homeWidgetTest';