Skip to content

Commit

Permalink
feat: Add requestPinWidget method (ABausG#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
tenhobi authored Jan 15, 2024
1 parent daea9c1 commit 301703f
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
```

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down
8 changes: 6 additions & 2 deletions ios/Classes/SwiftHomeWidgetPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
28 changes: 28 additions & 0 deletions lib/home_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions test/home_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ void main() {
return Future.value(launchUri);
case 'registerBackgroundCallback':
return true;
case 'requestPinWidget':
return null;
case 'isRequestPinWidgetSupported':
return true;
}
});
});
Expand Down Expand Up @@ -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';
Expand Down

0 comments on commit 301703f

Please sign in to comment.