├── .github
├── .cspell
│ └── names_dictionary.txt
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── assets
│ ├── build_phases.png
│ ├── demo_android.png
│ ├── demo_ios.png
│ ├── target.png
│ ├── target_membership.png
│ └── widget_extension.png
├── cspell.yaml
├── pull_request_template.md
└── workflows
│ ├── flutter-beta.yml
│ ├── main.yml
│ ├── release-prepare.yml
│ ├── release-publish.yml
│ ├── release-tag.yml
│ ├── spellcheck.yml
│ └── title-validator.yml
├── .gitignore
├── CHANGELOG.md
├── README.md
├── docs.json
├── docs
├── android-xml
│ ├── detect-clicks.mdx
│ ├── interactive-widgets.mdx
│ ├── overview.mdx
│ ├── render-flutter-widget.mdx
│ └── setup.mdx
├── assets
│ ├── configurable
│ │ └── ios
│ │ │ ├── app-group.webp
│ │ │ ├── app-intent-target-membership.webp
│ │ │ ├── configuration-in-flutter.webp
│ │ │ ├── configured-widgets.webp
│ │ │ ├── create-widget-extension-ios-with-configuration.webp
│ │ │ ├── intent-configuration.webp
│ │ │ ├── simple-parameter.webp
│ │ │ ├── siri-configuration-in-flutter.webp
│ │ │ ├── siri-configured-example.webp
│ │ │ ├── siri-created-type.webp
│ │ │ ├── siri-extension-dynamic-option.webp
│ │ │ ├── siri-extension-target-membership.webp
│ │ │ ├── siri-intent-file.webp
│ │ │ ├── siri-intents-extension.webp
│ │ │ ├── siri-new-type.webp
│ │ │ ├── siri-select-type.webp
│ │ │ ├── widget-with-name-configuration.webp
│ │ │ └── world-to-flutter.mp4
│ ├── create-widget-extension-ios.webp
│ ├── lockscreen.webp
│ └── pin-widget.gif
├── features
│ ├── analytics.mdx
│ ├── background-updates.mdx
│ ├── configurable-widgets.mdx
│ ├── detect-clicks.mdx
│ ├── interactive-widgets.mdx
│ ├── ios-lock-screen.mdx
│ ├── pin-widget.mdx
│ └── render-flutter-widgets.mdx
├── index.mdx
├── setup
│ ├── android.mdx
│ └── ios.mdx
└── usage
│ ├── sync-data.mdx
│ └── update-widget.mdx
├── examples
└── configurable_widget
│ ├── .gitignore
│ ├── .metadata
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── ios
│ ├── .gitignore
│ ├── ConfigurableWidget
│ │ ├── AppIntent.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── WidgetBackground.colorset
│ │ │ │ └── Contents.json
│ │ ├── ConfigurableWidget.swift
│ │ ├── ConfigurableWidgetBundle.swift
│ │ ├── Info.plist
│ │ └── Intents.intentdefinition
│ ├── ConfigurableWidgetExtension.entitlements
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── PunctuationIntent
│ │ ├── Info.plist
│ │ ├── IntentHandler.swift
│ │ └── PunctuationIntent.entitlements
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── Runner-Bridging-Header.h
│ │ └── Runner.entitlements
│ ├── lib
│ └── main.dart
│ └── pubspec.yaml
├── melos.yaml
├── packages
└── home_widget
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── android
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── settings.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── es
│ │ └── antonborri
│ │ └── home_widget
│ │ ├── HomeWidgetBackgroundReceiver.kt
│ │ ├── HomeWidgetBackgroundService.kt
│ │ ├── HomeWidgetGlanceState.kt
│ │ ├── HomeWidgetGlanceWidgetReceiver.kt
│ │ ├── HomeWidgetIntent.kt
│ │ ├── HomeWidgetPlugin.kt
│ │ └── HomeWidgetProvider.kt
│ ├── dart_test.yaml
│ ├── example
│ ├── .gitignore
│ ├── .metadata
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── android
│ │ ├── .gitignore
│ │ ├── app
│ │ │ ├── build.gradle
│ │ │ ├── proguard-rules.pro
│ │ │ └── src
│ │ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ │ ├── main
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── es
│ │ │ │ │ │ └── antonborri
│ │ │ │ │ │ └── home_widget_example
│ │ │ │ │ │ ├── HomeWidgetExampleProvider.kt
│ │ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ │ └── glance
│ │ │ │ │ │ ├── HomeWidgetGlanceAppWidget.kt
│ │ │ │ │ │ └── HomeWidgetReceiver.kt
│ │ │ │ └── res
│ │ │ │ │ ├── drawable
│ │ │ │ │ ├── launch_background.xml
│ │ │ │ │ └── widget_background.xml
│ │ │ │ │ ├── layout
│ │ │ │ │ └── example_layout.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ │ └── xml
│ │ │ │ │ ├── home_widget_example.xml
│ │ │ │ │ └── home_widget_glance_example.xml
│ │ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ └── gradle-wrapper.properties
│ │ └── settings.gradle
│ ├── integration_test
│ │ ├── android_test.dart
│ │ └── ios_test.dart
│ ├── ios
│ │ ├── .gitignore
│ │ ├── Flutter
│ │ │ ├── AppFrameworkInfo.plist
│ │ │ ├── Debug.xcconfig
│ │ │ └── Release.xcconfig
│ │ ├── HomeWidgetExample
│ │ │ ├── Assets.xcassets
│ │ │ │ ├── AccentColor.colorset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── AppIcon.appiconset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ └── WidgetBackground.colorset
│ │ │ │ │ └── Contents.json
│ │ │ ├── HomeWidgetExample.swift
│ │ │ └── Info.plist
│ │ ├── HomeWidgetExampleExtension.entitlements
│ │ ├── Podfile
│ │ ├── Runner.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace
│ │ │ │ └── xcshareddata
│ │ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ │ └── WorkspaceSettings.xcsettings
│ │ │ └── xcshareddata
│ │ │ │ └── xcschemes
│ │ │ │ └── Runner.xcscheme
│ │ ├── Runner.xcworkspace
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ ├── Runner
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets
│ │ │ │ ├── AppIcon.appiconset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── LaunchImage.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── LaunchImage.png
│ │ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ │ └── README.md
│ │ │ ├── BackgroundIntent.swift
│ │ │ ├── Base.lproj
│ │ │ │ ├── LaunchScreen.storyboard
│ │ │ │ └── Main.storyboard
│ │ │ ├── Info.plist
│ │ │ ├── Runner-Bridging-Header.h
│ │ │ └── Runner.entitlements
│ │ └── RunnerTests
│ │ │ └── RunnerTests.swift
│ ├── lib
│ │ └── main.dart
│ ├── pubspec.yaml
│ └── test_driver
│ │ └── integration_test.dart
│ ├── ios
│ ├── .gitignore
│ ├── Assets
│ │ └── .gitkeep
│ ├── Classes
│ │ ├── HomeWidgetBackgroundWorker.swift
│ │ └── HomeWidgetPlugin.swift
│ └── home_widget.podspec
│ ├── lib
│ ├── home_widget.dart
│ └── src
│ │ ├── home_widget.dart
│ │ ├── home_widget_callback_dispatcher.dart
│ │ └── home_widget_info.dart
│ ├── pub
│ └── screenshots
│ │ ├── android.png
│ │ └── ios-counter.gif
│ ├── pubspec.yaml
│ └── test
│ ├── background_test.dart
│ ├── goldens
│ └── render-flutter-widget.png
│ ├── home_widget_info_test.dart
│ ├── home_widget_test.dart
│ └── mocks.dart
└── pubspec.yaml
/.github/.cspell/names_dictionary.txt:
--------------------------------------------------------------------------------
1 | # specific people's names and/or usernames
2 | mchudy # github.com/mchudy
3 | milindgoel15 # github.com/milindgoel15
4 | mattrltrent # github.com/mattrltrent
5 | eliasto # github.com/eliasto
6 | leighajarett # github.com/leighajarett
7 | ColinSchmale # github.com/ColinSchmale
8 | linziyou # github.com/linziyou0601
9 | roly # github.com/roly151
10 | aaronkelton # github.com/aaronkelton
11 | hadysata # github.com/hadysata
12 | Verbeeck # github.com/NicolaVerbeeck
13 | ronnieeeeee # github.com/ronnieeeeee
14 | josepedromonteiro # github.com/josepedromonteiro
15 | stepushchik # github.com/stepushchik-denis-gismart
16 | gismart # github.com/stepushchik-denis-gismart
17 | aljkor # github.com/aljkor
18 | mgonzalezc # github.com/mgonzalezc
19 | subosito # github.com/subosito
20 | bluefireteam # github.com/bluefireteam
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: abausg
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: You discovered a Bug in your Homescreen Widget / in the home_widget Plugin
3 | labels: ["bug"]
4 |
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | When reporting a bug, please read this complete template and fill in all the questions in order to get a better response! Before filing a bug please make sure you read the documentation, check for related issues and discussions.
10 | - type: textarea
11 | id: what-happened
12 | attributes:
13 | label: What happened?
14 | description: Tell us, what happened?
15 | validations:
16 | required: true
17 |
18 | - type: textarea
19 | id: expectation
20 | attributes:
21 | label: What do you expect?
22 | description: Also tell us, what behavior did you expect?
23 | validations:
24 | required: true
25 |
26 | - type: textarea
27 | id: logs
28 | attributes:
29 | label: Relevant log output
30 | description: If you have any debug / error logging, please fill it here within the code block below
31 | render: shell
32 |
33 | - type: textarea
34 | attributes:
35 | label: Execute in a terminal and put output into the code block below
36 | value: 'Output of: flutter doctor -v'
37 |
38 | - type: dropdown
39 | id: affected-platforms
40 | attributes:
41 | label: On which Platform do you experience this issue?
42 | multiple: true
43 | options:
44 | - Android
45 | - iOS
46 | validations:
47 | required: true
48 |
49 | - type: textarea
50 | id: other-information
51 | attributes:
52 | label: Other information
53 | description: Do you have any other useful information about this bug report? Please write it down here
54 |
55 | - type: checkboxes
56 | id: terms
57 | attributes:
58 | label: Are you interested in working on a PR for this?
59 | options:
60 | - label: I want to work on this
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: I need a help with building my Widget.
4 | url: https://github.com/ABausG/home_widget/discussions
5 | about: Have a look at the discussions, maybe your question is already answered. Or the community can help you!
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest a new feature for home_widget.
3 | labels: [ "enhancement" ]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | When suggesting a feature, please read this complete form and fill in all the questions in order to get a better response!
9 | - type: textarea
10 | id: problem-to-solve
11 | attributes:
12 | label: Problem to solve
13 | description: Which problem would be solved with this feature?
14 | validations:
15 | required: true
16 | - type: textarea
17 | id: proposal
18 | attributes:
19 | label: Proposal
20 | description: What do you propose as a solution? Add as much information as you can!
21 | validations:
22 | required: true
23 | - type: textarea
24 | id: more-information
25 | attributes:
26 | label: More information
27 | description: Do you have any other useful information about this feature report? Please write it down here. Possible helpful information are references to other sites/repositories.
28 | - type: dropdown
29 | id: affected-platforms
30 | attributes:
31 | label: Which Platform would be improved?
32 | multiple: true
33 | options:
34 | - Android
35 | - iOS
36 | - type: checkboxes
37 | id: other
38 | attributes:
39 | label: Other
40 | options:
41 | - label: Are you interested in working on a PR for this?
--------------------------------------------------------------------------------
/.github/assets/build_phases.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/build_phases.png
--------------------------------------------------------------------------------
/.github/assets/demo_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/demo_android.png
--------------------------------------------------------------------------------
/.github/assets/demo_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/demo_ios.png
--------------------------------------------------------------------------------
/.github/assets/target.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/target.png
--------------------------------------------------------------------------------
/.github/assets/target_membership.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/target_membership.png
--------------------------------------------------------------------------------
/.github/assets/widget_extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/.github/assets/widget_extension.png
--------------------------------------------------------------------------------
/.github/cspell.yaml:
--------------------------------------------------------------------------------
1 | version: "0.2"
2 | ignorePaths:
3 | [
4 | "**/build/**",
5 | "**/coverage",
6 | "**/*.xcscheme",
7 | "**/*.storyboard",
8 | "**/GeneratedPluginRegistrant.m",
9 | "**/GeneratedPluginRegistrant.java",
10 | "**/*.pbxproj",
11 | "**/*.xcconfig",
12 | "**/**/*.podspec",
13 | "**/Info.plist",
14 | "**/*.xcassets",
15 | "**/*.xcworkspace",
16 | "**/*.xcodeproj",
17 | "**/Pods/Target Support Files/",
18 | "**/Pods/Local Podspecs",
19 | "**/gradlew",
20 | "**/gradlew.bat",
21 | "**/gradle-wrapper.properties",
22 | "**/AppFrameworkInfo.plist",
23 | "**/gradle.properties",
24 | "cspell.yaml",
25 | "**/build.gradle",
26 | "**/proguard-rules.pro",
27 | "**/.github/**",
28 | "**/.gitignore",
29 | "**/*.intentdefinition"
30 | ]
31 | dictionaries:
32 | - names
33 | dictionaryDefinitions:
34 | - name: names
35 | path: .cspell/names_dictionary.txt
36 | words:
37 | - antonborries
38 | - Borries
39 | - abausg
40 | - antonborri
41 | - mocktail
42 | - Goldens
43 | - cupertino
44 | - workmanager
45 | - cocoapods
46 | - renderview
47 | - appex
48 | - pinability
49 | - chào
50 | - titleclicked
51 | - NSURL
52 | - xcconfig
53 | - podhelper
54 | - podfile
55 | - realpath
56 | - appwidget
57 | - Millis # abbreviation for Milliseconds
58 | - androidx
59 | - Jetpack
60 | - kotlinx
61 | - lateinit
62 | - prefs # short for preferences
63 | - mipmap # android image format
64 | - nullsafety
65 | - Deeplinks
66 | - Deque
67 | - ktfmt
68 | - libexec
69 | - SRCROOT
70 | - Codelab
71 | - pubspec
72 | - Siri
73 | - objc
74 | - typealias
75 | - xcodeproj
76 | - pbxproj
77 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | # Description
9 |
15 | Replace this text.
16 |
17 | ## Checklist
18 |
22 |
23 | - [ ] I have updated/added tests for ALL new/updated/fixed functionality.
24 | - [ ] I have updated/added relevant documentation and added code (documentation) comments where necessary.
25 | - [ ] I have updated/added relevant examples in `example` or documentation.
26 |
27 |
28 | ## Breaking Change?
29 |
36 |
37 | - [ ] Yes, this PR is a breaking change.
38 | - [ ] No, this PR is not a breaking change.
39 |
40 |
46 |
47 |
48 | ## Related Issues
49 |
54 |
55 |
56 | [Conventional Commit]: https://conventionalcommits.org
57 | [CHANGELOG]: https://github.com/abausg/home_widget/blob/main/CHANGELOG.md
58 |
--------------------------------------------------------------------------------
/.github/workflows/flutter-beta.yml:
--------------------------------------------------------------------------------
1 | name: Build Flutter Beta
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - flutter-beta
8 | pull_request:
9 | branches:
10 | - flutter-beta
11 |
12 | concurrency:
13 | group: ${{ github.workflow }}-${{ github.ref }}
14 | cancel-in-progress: true
15 |
16 | jobs:
17 | quality:
18 | name: Quality Checks
19 | runs-on: macos-14
20 | defaults:
21 | run:
22 | working-directory: packages/home_widget
23 |
24 | steps:
25 | - uses: actions/checkout@v2
26 |
27 | - uses: subosito/flutter-action@v1
28 | with:
29 | channel: beta
30 | - uses: bluefireteam/melos-action@v3
31 | - name: Analyze
32 | run: melos analyze
33 | - name: Install Formatters
34 | run: brew install swift-format ktfmt
35 | - name: Format
36 | run: melos format:all
37 | - name: Publishability
38 | run: flutter pub publish --dry-run
39 | - name: Test
40 | run: flutter test --coverage
41 | - name: Archieve Golden Failures
42 | if: failure()
43 | uses: actions/upload-artifact@v3
44 | with:
45 | name: Golden failures
46 | retention-days: 2
47 | path: |
48 | **/test/**/failures/**/*.*
49 | - name: Upload coverage to Codecov
50 | uses: codecov/codecov-action@v1
51 | with:
52 | token: ${{ secrets.CODECOV_TOKEN }}
53 | path: ./packages/home_widget/coverage/lcov.info
54 |
55 | android:
56 | name: Android Integration Tests
57 | runs-on: ubuntu-latest
58 |
59 | steps:
60 | - uses: actions/checkout@v2
61 | - uses: subosito/flutter-action@v1
62 | with:
63 | channel: beta
64 | - uses: bluefireteam/melos-action@v3
65 | - name: Enable KVM
66 | run: |
67 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
68 | sudo udevadm control --reload-rules
69 | sudo udevadm trigger --name-match=kvm
70 | - name: Set up JDK 11
71 | uses: actions/setup-java@v4
72 | with:
73 | distribution: 'temurin'
74 | java-version: '11'
75 | - name: Run Android Integration Tests
76 | uses: reactivecircus/android-emulator-runner@v2
77 | with:
78 | api-level: 29
79 | script: flutter test integration_test/android_test.dart -d emulator-5554
80 | working-directory: packages/home_widget/example
81 |
82 | # iOS Test based on https://medium.com/flutter-community/run-flutter-driver-tests-on-github-actions-13c639c7e4ab
83 | # by @kate_sheremet
84 | ios:
85 | name: iOS Integration Tests
86 | strategy:
87 | matrix:
88 | device:
89 | - "iPhone 14"
90 | fail-fast: false
91 | runs-on: macos-14
92 | defaults:
93 | run:
94 | working-directory: packages/home_widget/example
95 | steps:
96 | - uses: actions/checkout@v2
97 | - uses: maxim-lobanov/setup-xcode@v1
98 | with:
99 | xcode-version: latest
100 | - uses: subosito/flutter-action@v1
101 | with:
102 | channel: beta
103 | - uses: bluefireteam/melos-action@v3
104 | - uses: futureware-tech/simulator-action@v1
105 | id: simulator
106 | with:
107 | model: ${{ matrix.device }}
108 | - name: "Run iOS integration tests"
109 | run: flutter test integration_test/ios_test.dart -d ${{steps.simulator.outputs.udid}}
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - main
8 | - dev
9 | pull_request:
10 | branches:
11 | - main
12 | - dev
13 |
14 | concurrency:
15 | group: ${{ github.workflow }}-${{ github.ref }}
16 | cancel-in-progress: true
17 |
18 | jobs:
19 | quality:
20 | name: Quality Checks
21 | runs-on: macos-15
22 | defaults:
23 | run:
24 | working-directory: packages/home_widget
25 |
26 | steps:
27 | - uses: actions/checkout@v2
28 |
29 | - uses: subosito/flutter-action@v1
30 | with:
31 | channel: stable
32 | - uses: bluefireteam/melos-action@v3
33 | - name: Analyze
34 | run: melos analyze
35 | - name: Install Formatters
36 | run: brew install swift-format ktfmt
37 | - name: Format
38 | run: melos format:all
39 | - name: Publishability
40 | run: flutter pub publish --dry-run
41 | - name: Test
42 | run: flutter test --coverage
43 | - name: Archieve Golden Failures
44 | if: failure()
45 | uses: actions/upload-artifact@v4
46 | with:
47 | name: Golden failures
48 | retention-days: 2
49 | path: |
50 | **/test/**/failures/**/*.*
51 | - name: Upload coverage to Codecov
52 | uses: codecov/codecov-action@v1
53 | with:
54 | token: ${{ secrets.CODECOV_TOKEN }}
55 | path: ./packages/home_widget/coverage/lcov.info
56 |
57 | android:
58 | name: Android Integration Tests
59 | runs-on: ubuntu-latest
60 |
61 | steps:
62 | - uses: actions/checkout@v2
63 | - uses: subosito/flutter-action@v1
64 | with:
65 | channel: stable
66 | - uses: bluefireteam/melos-action@v3
67 | - name: Enable KVM
68 | run: |
69 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
70 | sudo udevadm control --reload-rules
71 | sudo udevadm trigger --name-match=kvm
72 | - name: Set up JDK 21
73 | uses: actions/setup-java@v4
74 | with:
75 | distribution: 'temurin'
76 | java-version: '21'
77 | - name: Run Android Integration Tests
78 | uses: reactivecircus/android-emulator-runner@v2
79 | with:
80 | api-level: 29
81 | script: flutter test integration_test/android_test.dart -d emulator-5554
82 | working-directory: packages/home_widget/example
83 |
84 | # iOS Test based on https://medium.com/flutter-community/run-flutter-driver-tests-on-github-actions-13c639c7e4ab
85 | # by @kate_sheremet
86 | ios:
87 | name: iOS Integration Tests
88 | strategy:
89 | matrix:
90 | device:
91 | - "iPhone 15"
92 | fail-fast: false
93 | runs-on: macos-15
94 | defaults:
95 | run:
96 | working-directory: packages/home_widget/example
97 | steps:
98 | - uses: actions/checkout@v2
99 | - uses: maxim-lobanov/setup-xcode@v1
100 | with:
101 | xcode-version: latest
102 | - uses: subosito/flutter-action@v1
103 | with:
104 | channel: stable
105 | - uses: bluefireteam/melos-action@v3
106 | - uses: futureware-tech/simulator-action@v1
107 | id: simulator
108 | with:
109 | model: ${{ matrix.device }}
110 | - name: "Run iOS integration tests"
111 | run: flutter test integration_test/ios_test.dart -d ${{steps.simulator.outputs.udid}}
--------------------------------------------------------------------------------
/.github/workflows/release-prepare.yml:
--------------------------------------------------------------------------------
1 | name: Prepare release
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | prerelease:
6 | description: 'Version as prerelease'
7 | required: false
8 | default: false
9 | type: boolean
10 |
11 | jobs:
12 | prepare-release:
13 | name: Prepare release
14 | permissions:
15 | contents: write
16 | pull-requests: write
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | fetch-depth: 0
22 | - uses: subosito/flutter-action@v2
23 | - uses: bluefireteam/melos-action@v3
24 | with:
25 | run-versioning: ${{ inputs.prerelease == false }}
26 | run-versioning-prerelease: ${{ inputs.prerelease == true }}
27 | publish-dry-run: true
28 | create-pr: true
29 | git-email: github@antonborri.es
30 | git-name: Melos Action
--------------------------------------------------------------------------------
/.github/workflows/release-publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish packages
2 | on:
3 | push:
4 | tags:
5 | - 'home_widget-v*'
6 | workflow_dispatch:
7 |
8 | jobs:
9 | publish-packages:
10 | name: Publish packages
11 | permissions:
12 | contents: write
13 | id-token: write
14 | runs-on: [ ubuntu-latest ]
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: subosito/flutter-action@v2
18 | - uses: bluefireteam/melos-action@v3
19 | with:
20 | publish: true
21 | git-email: github@antonborri.es
22 | git-name: Melos Action
--------------------------------------------------------------------------------
/.github/workflows/release-tag.yml:
--------------------------------------------------------------------------------
1 | name: Tag release
2 | on:
3 | push:
4 | branches: [main]
5 |
6 | jobs:
7 | publish-packages:
8 | name: Create tag for a release
9 | permissions:
10 | contents: write
11 | runs-on: [ ubuntu-latest ]
12 | if: contains(github.event.head_commit.message, 'chore(release)')
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: subosito/flutter-action@v2
16 | - uses: bluefireteam/melos-action@v3
17 | with:
18 | tag: true
--------------------------------------------------------------------------------
/.github/workflows/spellcheck.yml:
--------------------------------------------------------------------------------
1 | name: Spellcheck
2 |
3 | on:
4 | pull_request:
5 |
6 | concurrency:
7 | group: ${{ github.workflow }}-${{ github.ref }}
8 | cancel-in-progress: true
9 |
10 | jobs:
11 | test:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: streetsidesoftware/cspell-action@v6
16 | with:
17 | config: .github/cspell.yaml
--------------------------------------------------------------------------------
/.github/workflows/title-validator.yml:
--------------------------------------------------------------------------------
1 | # See https://github.com/amannn/action-semantic-pull-request
2 | name: 'PR Title is Conventional'
3 |
4 | on:
5 | pull_request_target:
6 | types:
7 | - opened
8 | - edited
9 | - synchronize
10 |
11 | jobs:
12 | main:
13 | name: Validate PR title
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: amannn/action-semantic-pull-request@v5
17 | env:
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 | with:
20 | types: |
21 | build
22 | chore
23 | ci
24 | docs
25 | feat
26 | fix
27 | perf
28 | refactor
29 | revert
30 | style
31 | test
32 | subjectPattern: ^[A-Z].+$
33 | subjectPatternError: |
34 | The subject of the PR must begin with an uppercase letter.
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | .idea
9 |
10 | # Miscellaneous
11 | *.class
12 | *.lock
13 | *.log
14 | *.pyc
15 | *.swp
16 | .DS_Store
17 | .atom/
18 | .buildlog/
19 | .history
20 | .svn/
21 |
22 | # IntelliJ related
23 | *.iml
24 | *.ipr
25 | *.iws
26 | .idea/
27 |
28 | # Visual Studio Code related
29 | .classpath
30 | .project
31 | .settings/
32 | .vscode/
33 |
34 | # Flutter repo-specific
35 | /bin/cache/
36 | /bin/mingit/
37 | /dev/benchmarks/mega_gallery/
38 | /dev/bots/.recipe_deps
39 | /dev/bots/android_tools/
40 | /dev/devicelab/ABresults*.json
41 | /dev/docs/doc/
42 | /dev/docs/flutter.docs.zip
43 | /dev/docs/lib/
44 | /dev/docs/pubspec.yaml
45 | /dev/integration_tests/**/xcuserdata
46 | /dev/integration_tests/**/Pods
47 | /packages/flutter/coverage/
48 | version
49 | analysis_benchmark.json
50 |
51 | # packages file containing multi-root paths
52 | .packages.generated
53 |
54 | # Flutter/Dart/Pub related
55 | **/doc/api/
56 | .dart_tool/
57 | .flutter-plugins
58 | .flutter-plugins-dependencies
59 | **/generated_plugin_registrant.dart
60 | .packages
61 | .pub-cache/
62 | .pub/
63 | build/
64 | flutter_*.png
65 | linked_*.ds
66 | unlinked.ds
67 | unlinked_spec.ds
68 |
69 | # Android related
70 | **/android/**/gradle-wrapper.jar
71 | **/android/.gradle
72 | **/android/captures/
73 | **/android/gradlew
74 | **/android/gradlew.bat
75 | **/android/local.properties
76 | **/android/**/GeneratedPluginRegistrant.java
77 | **/android/key.properties
78 | *.jks
79 |
80 | # iOS/XCode related
81 | **/ios/**/*.mode1v3
82 | **/ios/**/*.mode2v3
83 | **/ios/**/*.moved-aside
84 | **/ios/**/*.pbxuser
85 | **/ios/**/*.perspectivev3
86 | **/ios/**/*sync/
87 | **/ios/**/.sconsign.dblite
88 | **/ios/**/.tags*
89 | **/ios/**/.vagrant/
90 | **/ios/**/DerivedData/
91 | **/ios/**/Icon?
92 | **/ios/**/Pods/
93 | **/ios/**/.symlinks/
94 | **/ios/**/profile
95 | **/ios/**/xcuserdata
96 | **/ios/.generated/
97 | **/ios/Flutter/.last_build_id
98 | **/ios/Flutter/App.framework
99 | **/ios/Flutter/Flutter.framework
100 | **/ios/Flutter/Flutter.podspec
101 | **/ios/Flutter/Generated.xcconfig
102 | **/ios/Flutter/app.flx
103 | **/ios/Flutter/app.zip
104 | **/ios/Flutter/flutter_assets/
105 | **/ios/Flutter/flutter_export_environment.sh
106 | **/ios/ServiceDefinitions.json
107 | **/ios/Runner/GeneratedPluginRegistrant.*
108 |
109 | # macOS
110 | **/macos/Flutter/GeneratedPluginRegistrant.swift
111 | **/macos/Flutter/Flutter-Debug.xcconfig
112 | **/macos/Flutter/Flutter-Release.xcconfig
113 | **/macos/Flutter/Flutter-Profile.xcconfig
114 |
115 | # Coverage
116 | coverage/
117 |
118 | # Symbols
119 | app.*.symbols
120 |
121 | # Exceptions to above rules.
122 | !**/ios/**/default.mode1v3
123 | !**/ios/**/default.mode2v3
124 | !**/ios/**/default.pbxuser
125 | !**/ios/**/default.perspectivev3
126 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
127 | !/dev/ci/**/Gemfile.lock
128 | .gradle
129 | *.xcworkspacedata
130 | *.jar
131 |
132 | # don't check in golden failure output
133 | **/failures/*.png
134 | pubspec_overrides.yaml
135 | .cxx
136 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## 2025-05-25
7 |
8 | ### Changes
9 |
10 | ---
11 |
12 | Packages with breaking changes:
13 |
14 | - [`home_widget` - `v0.8.0`](#home_widget---v080)
15 |
16 | Packages with other changes:
17 |
18 | - There are no other changes in this release.
19 |
20 | ---
21 |
22 | #### `home_widget` - `v0.8.0`
23 |
24 | - **FEAT**: Configurable Widgets support for iOS ([#348](https://github.com/abausg/home_widget/issues/348)). ([e8809d89](https://github.com/abausg/home_widget/commit/e8809d89c15348cb3ded7769278add51ce4b2379))
25 | - **FEAT**: Add triggeredFromHomeWidget flag to updateWidget on Android ([#315](https://github.com/abausg/home_widget/issues/315)). ([dc2b9302](https://github.com/abausg/home_widget/commit/dc2b9302c30e6690f1f084e4fad2b1041a1d8c88))
26 | - **BREAKING** **FEAT**: Default to the device pixel ratio ([#304](https://github.com/abausg/home_widget/issues/304)). ([90522de3](https://github.com/abausg/home_widget/commit/90522de374d5411842e84031453756eeec25ac9e))
27 | - **BREAKING** **CHORE**: Enable strong language analyzer ([#305](https://github.com/abausg/home_widget/issues/305)). ([1b5df0b3](https://github.com/abausg/home_widget/commit/1b5df0b36e0ccf0c0ffef234faf0ed8731f9ade4))
28 |
29 |
30 | ## 2025-02-06
31 |
32 | ### Changes
33 |
34 | ---
35 |
36 | Packages with breaking changes:
37 |
38 | - There are no breaking changes in this release.
39 |
40 | Packages with other changes:
41 |
42 | - [`home_widget` - `v0.7.0+1`](#home_widget---v0701)
43 |
44 | ---
45 |
46 | #### `home_widget` - `v0.7.0+1`
47 |
48 | - **FIX**: Runtime error when starting App from Widget on Android 15 ([#330](https://github.com/abausg/home_widget/issues/330)). ([64a38eb3](https://github.com/abausg/home_widget/commit/64a38eb39fb6ef20342ac2a5eaf5c9bedf2e6c75))
49 | - **DOCS**: Move Documentation to docs.page ([#287](https://github.com/abausg/home_widget/issues/287)). ([52ee746a](https://github.com/abausg/home_widget/commit/52ee746ad1d1dd9ef2aa9f1c61e482825f73d9d9))
50 | - **DOCS**: Improve pubspec metadata ([#283](https://github.com/abausg/home_widget/issues/283)). ([f23c63e8](https://github.com/abausg/home_widget/commit/f23c63e8d393708aaf197ccb54b391d81a765a19))
51 |
52 |
53 | ## 2024-08-28
54 |
55 | ### Changes
56 |
57 | ---
58 |
59 | Packages with breaking changes:
60 |
61 | - There are no breaking changes in this release.
62 |
63 | Packages with other changes:
64 |
65 | - [`home_widget` - `v0.7.0`](#home_widget---v070)
66 |
67 | ---
68 |
69 | #### `home_widget` - `v0.7.0`
70 |
71 | - **DOCS**: Move Documentation to docs.page ([#287](https://github.com/abausg/home_widget/issues/287)). ([52ee746a](https://github.com/abausg/home_widget/commit/52ee746ad1d1dd9ef2aa9f1c61e482825f73d9d9))
72 | - **DOCS**: Improve pubspec metadata ([#283](https://github.com/abausg/home_widget/issues/283)). ([f23c63e8](https://github.com/abausg/home_widget/commit/f23c63e8d393708aaf197ccb54b391d81a765a19))
73 |
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | packages/home_widget/README.md
--------------------------------------------------------------------------------
/docs.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "home_widget",
3 | "theme": "#567acb",
4 | "content": {
5 | "headerDepth": 4
6 | },
7 | "social": {
8 | "x": "@abausg",
9 | "github": "abausg",
10 | "linkedin": "/in/abausg"
11 | },
12 | "sidebar": [
13 | [
14 | "Overview",
15 | "/"
16 | ],
17 | [
18 | "Usage",
19 | [
20 | [
21 | "Sync Data",
22 | "/usage/sync-data"
23 | ],
24 | [
25 | "Update Widget",
26 | "/usage/update-widget"
27 | ]
28 | ]
29 | ],
30 | [
31 | "Platform Setup",
32 | [
33 | [
34 | "iOS",
35 | "/setup/ios"
36 | ],
37 | [
38 | "Android",
39 | "/setup/android"
40 | ]
41 | ]
42 | ],
43 | [
44 | "Features",
45 | [
46 | [
47 | "Render Flutter Widgets",
48 | "/features/render-flutter-widgets"
49 | ],
50 | [
51 | "Interactive Widgets",
52 | "/features/interactive-widgets"
53 | ],
54 | [
55 | "Detect Clicks",
56 | "/features/detect-clicks"
57 | ],
58 | [
59 | "Analytics",
60 | "/features/analytics"
61 | ],
62 | [
63 | "Configurable Widgets",
64 | "/features/configurable-widgets"
65 | ],
66 | [
67 | "iOS Lock Screen Widgets",
68 | "/features/ios-lock-screen"
69 | ],
70 | [
71 | "Pin Widget (Android)",
72 | "/features/pin-widget"
73 | ],
74 | [
75 | "Background Updates",
76 | "/features/background-updates"
77 | ]
78 | ]
79 | ],
80 | [
81 | "Android XML",
82 | [
83 | [
84 | "Overview",
85 | "/android-xml/overview"
86 | ],
87 | [
88 | "Setup",
89 | "/android-xml/setup"
90 | ],
91 | [
92 | "Render Flutter Widgets",
93 | "/android-xml/render-flutter-widget"
94 | ],
95 | [
96 | "Interactive Widgets",
97 | "/android-xml/interactive-widgets"
98 | ],
99 | [
100 | "Detect Clicks",
101 | "/android-xml/detect-clicks"
102 | ]
103 | ]
104 | ]
105 | ]
106 | }
107 |
--------------------------------------------------------------------------------
/docs/android-xml/detect-clicks.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Detect Clicks
3 | description: Detecting Clicks on Android Widgets
4 | ---
5 |
6 | # Detect Clicks on with Android XML Widgets
7 |
8 | Add an `IntentFilter` to the `Activity` Section in your `AndroidManifest`
9 | ```
10 |
11 |
12 |
13 | ```
14 |
15 | In your WidgetProvider add a PendingIntent to your View using `HomeWidgetLaunchIntent.getActivity`
16 | ```kotlin
17 | val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
18 | context,
19 | MainActivity::class.java,
20 | Uri.parse("homeWidgetExample://message?message=$message"))
21 | setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData)
22 | ```
--------------------------------------------------------------------------------
/docs/android-xml/interactive-widgets.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Interactive Widgets
3 | description: How to create interactive Widgets with home_widget and Android XML Widgets
4 | ---
5 |
6 | # Interactive Widgets
7 |
8 | Follow the necessary steps to set up everything on the Flutter Side as described [here](/features/interactive-widgets#flutter-setup).
9 |
10 | 1. Add the necessary Receiver and Service to your `AndroidManifest.xml` file
11 | ```
12 |
13 |
14 |
15 |
16 |
17 |
19 | ```
20 | 2. Add a `HomeWidgetBackgroundIntent.getBroadcast` PendingIntent to the View you want to add a click listener to
21 | ```kotlin
22 | val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
23 | context,
24 | Uri.parse("homeWidgetExample://titleClicked")
25 | )
26 | setOnClickPendingIntent(R.id.widget_title, backgroundIntent)
27 | ```
28 |
--------------------------------------------------------------------------------
/docs/android-xml/overview.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Android XML
3 | description: home_widget and Android XML Widgets
4 | ---
5 |
6 | # Android XML Support
7 |
8 | home_widget supports Android Widgets created with XML. This allows you to create Widgets for your Android App using the home_widget Plugin.
9 | However going forward it is recommended to use the [Jetpack Glance](/setup/android) way to create Widgets home_widget.
10 |
11 | In the following pages you can still find information on how to use respective Features of home_widget with Android XML Widgets.
12 |
13 |
--------------------------------------------------------------------------------
/docs/android-xml/render-flutter-widget.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Render Flutter Widget
3 | description: Render Flutter Widgets in Android XML Widgets
4 | ---
5 |
6 | # Render Flutter Widgets
7 |
8 | 1. Add an image UI element to your xml file:
9 | ```xml
10 |
29 | ```
30 | 2. Update your Kotlin code to get the chart image and put it into the widget, if it exists.
31 | ```kotlin
32 | class NewsWidget : AppWidgetProvider() {
33 | override fun onUpdate(
34 | context: Context,
35 | appWidgetManager: AppWidgetManager,
36 | appWidgetIds: IntArray,
37 | ) {
38 | for (appWidgetId in appWidgetIds) {
39 | // Get reference to SharedPreferences
40 | val widgetData = HomeWidgetPlugin.getData(context)
41 | val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
42 | // Get chart image and put it in the widget, if it exists
43 | val imagePath = widgetData.getString("lineChart", null)
44 | val imageFile = File(imagePath)
45 | val imageExists = imageFile.exists()
46 | if (imageExists) {
47 | val myBitmap: Bitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
48 | setImageViewBitmap(R.id.widget_image, myBitmap)
49 | } else {
50 | println("image not found!, looked @: $imagePath")
51 | }
52 | // End new code
53 | }
54 | appWidgetManager.updateAppWidget(appWidgetId, views)
55 | }
56 | }
57 | }
58 | ```
--------------------------------------------------------------------------------
/docs/android-xml/setup.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Android XML Setup
3 | description: Setup home_widget and Widgets with Android XML
4 | ---
5 |
6 | # Android XML Setup
7 |
8 | ## Necessary Files
9 |
10 | ### Widget Configuration
11 | In `android/app/src/main/res/xml` you need to create a configuration file.
12 | In here you can configure properties used for things like size constraints and preview layouts.
13 | ```xml
14 |
20 |
21 | ```
22 | For more Information on the possible contents of this File check the official Android Documentation [here](https://developer.android.com/develop/ui/views/appwidgets#AppWidgetProviderInfo)
23 |
24 |
25 | ### Widget Layout
26 | Create Widget Layout inside `android/app/src/main/res/layout`
27 |
28 | This file contains the Layout of your Widget. Note that this can only use RemoteViews to build the Layout.
29 |
30 | ```xml
31 |
32 |
40 |
47 |
48 | ```
49 |
50 | ### WidgetProvider
51 | The `WidgetProvider` is used to bind Data to the Layout.
52 | For convenience, you can extend from `HomeWidgetProvider` which gives you access to a SharedPreferences Object with the Data in the `onUpdate` method.
53 |
54 | ```kotlin
55 | // Remember to set a package in order for home_widget to find the Provider
56 | package es.antonborri.home_widget_counter
57 |
58 | class CounterWidgetProvider : HomeWidgetProvider() {
59 | override fun onUpdate(
60 | context: Context,
61 | appWidgetManager: AppWidgetManager,
62 | appWidgetIds: IntArray,
63 | widgetData: SharedPreferences) {
64 | appWidgetIds.forEach { widgetId ->
65 | val views = RemoteViews(context.packageName, R.layout.counter_widget).apply {
66 | val count = widgetData.getInt("counter", 0)
67 | setTextViewText(R.id.text_counter, count.toString())
68 | }
69 | // This line is important to trigger the update
70 | appWidgetManager.updateAppWidget(widgetId, views)
71 | }
72 | }
73 | }
74 | ```
75 |
76 | In case you don't want to use the convenience Method you can access the Data using
77 | ```kotlin
78 | import es.antonborri.home_widget.HomeWidgetPlugin
79 | ...
80 | HomeWidgetPlugin.getData(context)
81 | ```
82 | which will give you access to the same SharedPreferences
83 |
84 | ### Add WidgetReceiver to AndroidManifest
85 | ```xml
86 |
87 |
88 |
89 |
90 |
92 |
93 | ```
94 |
95 | ## More Information
96 | For more Information on how to create and configure Android Widgets, check out [this guide](https://developer.android.com/develop/ui/views/appwidgets) on the Android Developers Page.
97 |
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/app-group.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/app-group.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/app-intent-target-membership.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/app-intent-target-membership.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/configuration-in-flutter.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/configuration-in-flutter.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/configured-widgets.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/configured-widgets.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/create-widget-extension-ios-with-configuration.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/create-widget-extension-ios-with-configuration.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/intent-configuration.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/intent-configuration.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/simple-parameter.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/simple-parameter.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-configuration-in-flutter.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-configuration-in-flutter.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-configured-example.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-configured-example.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-created-type.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-created-type.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-extension-dynamic-option.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-extension-dynamic-option.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-extension-target-membership.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-extension-target-membership.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-intent-file.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-intent-file.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-intents-extension.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-intents-extension.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-new-type.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-new-type.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/siri-select-type.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/siri-select-type.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/widget-with-name-configuration.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/widget-with-name-configuration.webp
--------------------------------------------------------------------------------
/docs/assets/configurable/ios/world-to-flutter.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/configurable/ios/world-to-flutter.mp4
--------------------------------------------------------------------------------
/docs/assets/create-widget-extension-ios.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/create-widget-extension-ios.webp
--------------------------------------------------------------------------------
/docs/assets/lockscreen.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/lockscreen.webp
--------------------------------------------------------------------------------
/docs/assets/pin-widget.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/docs/assets/pin-widget.gif
--------------------------------------------------------------------------------
/docs/features/analytics.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Analytics
3 | description: Check which Widgets Users have currently installed
4 | ---
5 |
6 | # Analytics
7 |
8 | Sometimes it can be useful to know which Widgets your Users have currently installed.
9 |
10 | Using home_widget you can check which Widgets a User currently has added to their HomeScreen
11 |
12 | ```dart
13 | final List info = await HomeWidget.getInstalledWidgets();
14 | ```
15 |
16 | This will give you respective Information about the Widgets a User has currently installed with respective platform specific Widget Information filled.
17 |
18 | Note that each combination of `iOSFamily`(Size) and `iOSKind`(Widget Type) will only appear once in the list due to limitations of iOS.
19 |
--------------------------------------------------------------------------------
/docs/features/background-updates.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Background Update
3 | description: Update your Widget while the App is in the Background
4 | ---
5 |
6 | # Background Update
7 | As the methods of HomeWidget are static it is possible to use HomeWidget in the background to update the Widget even when the App is in the background.
8 |
9 | The example App is using the [flutter_workmanager](https://pub.dev/packages/workmanager) plugin to achieve this.
10 | Please follow the Setup Instructions for flutter_workmanager (or your preferred background code execution plugin). Most notably make sure that Plugins get registered in iOS in order to be able to communicate with the HomeWidget Plugin.
11 | In case of flutter_workmanager this achieved by adding:
12 | ```swift
13 | WorkmanagerPlugin.setPluginRegistrantCallback { registry in
14 | GeneratedPluginRegistrant.register(with: registry)
15 | }
16 | ```
17 | to [AppDelegate.swift](example/ios/Runner/AppDelegate.swift)
--------------------------------------------------------------------------------
/docs/features/detect-clicks.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Detect Clicks
3 | description: Detect Clicks on Widgets from inside your App
4 | ---
5 |
6 | # Detect Clicks
7 |
8 | home_widget offers functionality to check if your App was launched by clicking on an element in the HomeScreen Widget.
9 |
10 |
11 | Note that this is not for Interactive Widgets. For this please check the relevant documentation [here](/features/interactive-widgets).
12 |
13 |
14 | To detect this in your App there are two methods:
15 |
16 | For when your App is started from the very background check:
17 | ```dart
18 | HomeWidget.initiallyLaunchedFromHomeWidget();
19 | ```
20 | this will return a `Future` with the Uri that was used to start the App.
21 |
22 | When your App is already running all Widget clicks are broadcast to a Stream provided via:
23 |
24 | ```dart
25 | HomeWidget.widgetClicked;
26 | ````
27 | which is a `Stream` that you can listen to to detect App Launches from the Widget.title
28 |
29 |
30 | ## Platform Setup
31 |
32 | In the following section you can learn how to add the necessary configurations to your native Widgets in order for clicks to bet detectable by home_widget.title
33 |
34 | ### iOS
35 |
36 | Add `.widgetUrl` to your WidgetComponent
37 | ```swift
38 | Text(entry.message)
39 | .font(.body)
40 | .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget"))
41 | ```
42 | In order to only detect Widget Links you need to add the queryParameter`homeWidget` to the URL
43 |
44 | ### Android
45 |
46 |
47 | Add an `IntentFilter` to the `Activity` Section in your `AndroidManifest`
48 | ```
49 |
50 |
51 |
52 | ```
53 |
54 | Add the following modifier to your Widget (import from HomeWidget)
55 | ```kotlin
56 | Text(
57 | message,
58 | style = TextStyle(fontSize = 18.sp),
59 | modifier = GlanceModifier.clickable(
60 | onClick = actionStartActivity(
61 | context,
62 | Uri.parse("homeWidgetExample://message?message=$message")
63 | )
64 | )
65 | )
66 | ```
--------------------------------------------------------------------------------
/docs/features/ios-lock-screen.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: iOS Lock Screen Widgets
3 | description: Create Widgets for the iOS Lock Screen
4 | ---
5 |
6 | # iOS Lock Screen Widgets
7 |
8 | On iOS, Lock Screen Widgets are a great way to show information to your users without them having to unlock their device.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Supported Families
17 | Technically, this works by adding another `family` to your widget's configuration.
18 |
19 | ```swift
20 | var body: some WidgetConfiguration {
21 | ...
22 | .description("Lock Screen Widgets")
23 | .supportedFamilies([
24 | .systemSmall,
25 | .systemMedium,
26 | // Accessory Widgets are available on the Lock Screen only
27 | .accessoryCircular
28 | ])
29 | ```
30 |
31 | ## Adjust Layout
32 |
33 | To adjust the layout of the widget, you can check which family/size is currently requested in the widget's layout code.
34 |
35 | ```swift
36 | struct LockScreenWidgetView: View {
37 | var entry: Provider.Entry
38 |
39 | // Detect the current Family
40 | @Environment(\.widgetFamily) var family
41 |
42 | var body: some View {
43 | if family == .accessoryCircular {
44 | // Return Widget for Circular Lock Screen Widget
45 | } else {
46 | // Build Widget for other families
47 | }
48 | }
49 | }
50 | ```
51 |
52 | For more information on accessory widgets, check out the [official Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/widgets#Interface-design).
53 |
54 | A full guide on how to add a Lock Screen Widget using home_widget can also be found in this [article](https://medium.com/@ABausG/ios-lockscreen-widgets-with-flutter-and-home-widget-0dfecc18cfa0).
--------------------------------------------------------------------------------
/docs/features/pin-widget.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pin Widgets (Android)
3 | description: Use Pin Widget to add widgets directly to the HomeScreen on Android.
4 | ---
5 |
6 | # Pin Widgets
7 |
8 | On Android, you can initiate an action to pin a widget to the HomeScreen, allowing your users to directly add your widget to their HomeScreen.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ```dart
17 | HomeWidget.requestPinWidget(
18 | name: 'HomeWidgetExampleProvider',
19 | androidName: 'HomeWidgetExampleProvider',
20 | qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
21 | );
22 | ```
23 |
24 | This method is only supported on [Android API 26+](https://developer.android.com/develop/ui/views/appwidgets/configuration#pin).
25 | If you want to check whether it is supported on the current device, use:
26 |
27 | ```dart
28 | HomeWidget.isRequestPinWidgetSupported();
29 | ```
--------------------------------------------------------------------------------
/docs/features/render-flutter-widgets.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Render Flutter Widgets
3 | description: User renderFlutterWidget to render Flutter Widgets to the Native Widgets
4 | ---
5 |
6 | # Render Flutter Widgets
7 |
8 | In some cases, you may not want to rewrite UI code in the native frameworks for your widgets. This works by generating a png file of the Flutter widget and save it to a shared container between your Flutter app and the home screen widget.
9 |
10 |
11 |
12 |
13 | Due to a limitation in `dart:ui` this method does not work when the App is fully in the background. In those cases you should try to build the UI natively.
14 |
15 |
16 | For example, say you have a chart in your Flutter app configured with `CustomPaint`:
17 |
18 | ```dart
19 | class LineChart extends StatelessWidget {
20 | const LineChart({
21 | super.key,
22 | });
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return CustomPaint(
27 | painter: LineChartPainter(),
28 | child: const SizedBox(
29 | height: 200,
30 | width: 200,
31 | ),
32 | );
33 | }
34 | }
35 | ```
36 |
37 |
38 |
39 | ## Flutter
40 |
41 | To render a Flutter widget to an image, use the `renderFlutterWidget` method:
42 |
43 | ```dart
44 | var path = await HomeWidget.renderFlutterWidget(
45 | const LineChart(),
46 | key: 'lineChart',
47 | logicalSize: const Size(400, 400),
48 | );
49 | ```
50 | - `LineChart()` is the widget that will be rendered as an image.
51 | - `key` is the key in the key/value storage on the device that stores the path of the file for easy retrieval on the native side
52 |
53 | ## iOS
54 |
55 | To retrieve the image and display it in a widget, you can use the following SwiftUI code:
56 |
57 | 1. In your `TimelineEntry` struct add a property to retrieve the path:
58 | ```swift
59 | struct MyEntry: TimelineEntry {
60 | …
61 | let lineChartPath: String
62 | }
63 | ```
64 |
65 | 2. Get the path from the `UserDefaults` in `getSnapshot`:
66 | ```swift
67 | func getSnapshot(
68 | ...
69 | let lineChartPath = userDefaults?.string(forKey: "lineChart") ?? "No screenshot available"
70 | ```
71 | 3. Create a `View` to display the chart and resize the image based on the `displaySize` of the widget:
72 | ```swift
73 | struct WidgetEntryView : View {
74 | …
75 | var ChartImage: some View {
76 | if let uiImage = UIImage(contentsOfFile: entry.lineChartPath) {
77 | let image = Image(uiImage: uiImage)
78 | .resizable()
79 | .frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center)
80 | return AnyView(image)
81 | }
82 | print("The image file could not be loaded")
83 | return AnyView(EmptyView())
84 | }
85 | …
86 | }
87 | ```
88 |
89 | 4. Display the chart in the body of the widget's `View`:
90 | ```swift
91 | VStack {
92 | Text(entry.title)
93 | Text(entry.description)
94 | ChartImage
95 | }
96 | ```
97 |
98 | ## Android
99 |
100 | On Android use the following code in your Glance Widget to display the Screenshot of the Flutter Widget
101 |
102 | ```kotlin
103 | // Access data
104 | val data = currentState.preferences
105 |
106 | // Get Path
107 | val imagePath = data.getString("lineChart", null)
108 |
109 | // Add Image to Compose Tree
110 | imagePath?.let {
111 | val bitmap = BitmapFactory.decodeFile(it)
112 | Image(androidx.glance.ImageProvider(bitmap), null)
113 | }
114 | ```
--------------------------------------------------------------------------------
/docs/setup/android.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Android Setup
3 | description: Setup home_widget on Android for your Flutter App using Jetpack Glance
4 | previousTitle: iOS Setup
5 | previous: /setup/ios
6 | ---
7 |
8 |
9 | # Android Setup
10 |
11 | Learn how to setup home_widget on Android for your Flutter App using Jetpack Glance.
12 |
13 |
14 | If you are looking for support for Android XML Widgets, please refer to the [Android XML](/android-xml/overview) section.
15 |
16 |
17 | ## Dependencies
18 |
19 | ### Jetpack Glance
20 |
21 | Add Jetpack Glance as a dependency to you app's Gradle File
22 | ```groovy
23 | implementation 'androidx.glance:glance-appwidget:LATEST-VERSION'
24 | ```
25 |
26 | ### Compose Support
27 | Enable Compose Support in your apps `build.gradle`
28 | ```groovy
29 | android {
30 | ...
31 | buildFeatures {
32 | compose true
33 | }
34 | }
35 | ```
36 |
37 | ## Necessary Files
38 |
39 | For the correct setup of HomeScreenWidgets you need to create a series of files.
40 |
41 | ### Widget Configuration
42 | In `android/app/src/main/res/xml` you need to create a configuration file.
43 | In here you can configure properties used for things like size constraints and preview layouts.
44 | ```xml
45 |
51 |
52 | ```
53 | For more Information on the possible contents of this File check the official Android Documentation [here](https://developer.android.com/develop/ui/views/appwidgets#AppWidgetProviderInfo)
54 |
55 | ### AppWidget
56 |
57 | The `GlanceAppWidget` is the file in which you define your Widget's layout. Should look something like this
58 |
59 | ```kotlin
60 | // Other imports...
61 | import HomeWidgetGlanceState
62 | import HomeWidgetGlanceStateDefinition
63 |
64 | class AppWidget : GlanceAppWidget() {
65 |
66 | override val stateDefinition: GlanceStateDefinition<*>?
67 | get() = HomeWidgetGlanceStateDefinition()
68 |
69 | override suspend fun provideGlance(context: Context, id: GlanceId) {
70 | provideContent {
71 | GlanceContent(context, currentState())
72 | }
73 | }
74 |
75 | @Composable
76 | private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
77 | val prefs = currentState.preferences
78 | val counter = prefs.getInt("counter", 0)
79 | Box(modifier = GlanceModifier.background(Color.White).padding(16.dp)) {
80 | Column() {
81 | Text(
82 | counter.toString()
83 | )
84 | }
85 | }
86 | }
87 | }
88 | ```
89 |
90 | Note the override for the `stateDefinition` this is what enables home_widget to update the Widget.
91 | ```kotlin
92 | override val stateDefinition: GlanceStateDefinition<*>?
93 | get() = HomeWidgetGlanceStateDefinition()
94 | ```
95 |
96 | ### WidgetReceiver
97 |
98 | To get automatic Updates you should extend from [HomeWidgetGlanceWidgetReceiver](android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetGlanceWidgetReceiver.kt)
99 |
100 | Your Receiver should then look like this, using the previously define `AppWidget` as the generic type.
101 |
102 | ```kotlin
103 | // Remember to set a package in order for home_widget to find the Receiver
104 | package es.antonborri.home_widget_example.glance
105 |
106 | import HomeWidgetGlanceWidgetReceiver
107 |
108 | class HomeWidgetReceiver : HomeWidgetGlanceWidgetReceiver() {
109 | override val glanceAppWidget = AppWidget()
110 | }
111 | ```
112 |
113 |
114 | ### Register Widget in AndroidManifest.xml
115 |
116 | Tie everything together by registering the Widget in your `AndroidManifest.xml`
117 | ```xml
118 |
120 |
121 |
122 |
123 |
126 |
127 | ```
128 |
--------------------------------------------------------------------------------
/docs/usage/sync-data.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Read and write Data
3 | description: Read and write Data
4 | ---
5 |
6 | # Read and Write Data
7 |
8 | By default home_widget uses UserDefaults on iOS and SharedPreferences on Android to store data.
9 | In this section it is explained how to save and read data from the Flutter App as well as how to access data from your HomeScreen Widgets
10 |
11 | ## Save Data
12 |
13 | In order to save Data call
14 | ```dart
15 | HomeWidget.saveWidgetData('id', data);
16 | ```
17 |
18 | ## Read Data
19 |
20 | To retrieve the current Data saved in the Widget call
21 | ```dart
22 | HomeWidget.getWidgetData('id', defaultValue: data);
23 | ```
24 |
25 | Check out the platform documentation of
26 | [iOS](/setup/ios#timelineentry--timelineprovider) and [Android](/setup/android#appwidget)
27 | to see how to access this data in your widget.
28 |
--------------------------------------------------------------------------------
/docs/usage/update-widget.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Update Widget
3 | description: How to Update a native Widget from Flutter
4 | nextTitle: iOS Setup
5 | next: /setup/android
6 | ---
7 |
8 | # Update Widget
9 |
10 | In order to initiate a reload of the HomeScreenWidget you need to call
11 | ```dart
12 | HomeWidget.updateWidget(
13 | name: 'HomeWidgetExampleProvider',
14 | androidName: 'HomeWidgetExampleProvider',
15 | iOSName: 'HomeWidgetExample',
16 | qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
17 | );
18 | ```
19 |
20 |
21 | Not all the arguments are required. Depending on your setup you might need to call different arguments of the function.
22 | For iOS either `name` or `iOSName` must match the `kind` that is defined for the Widget
23 | For Android either `name` or `androidName` must the class Name of your Widget Receiver. Alternatively you can point to the receivers full class using `qualifiedAndroidName`
24 |
25 |
26 |
27 | #### Android Glance
28 |
29 | To ensure your Android Glance Widget is getting updated you need to add the following snippet to your Android Glance Widget. Please also make sure you read the full documentation on [Android Glance](/setup/android) to ensure you have the correct setup.
30 |
31 | ```kotlin
32 | override val stateDefinition: GlanceStateDefinition<*>?
33 | get() = HomeWidgetGlanceStateDefinition()
34 | ```
35 |
36 |
37 |
--------------------------------------------------------------------------------
/examples/configurable_widget/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Symbolication related
35 | app.*.symbols
36 |
37 | # Obfuscation related
38 | app.*.map.json
39 |
40 | # Android Studio will place build artifacts here
41 | /android/app/debug
42 | /android/app/profile
43 | /android/app/release
44 |
--------------------------------------------------------------------------------
/examples/configurable_widget/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "b0850beeb25f6d5b10426284f506557f66181b36"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: b0850beeb25f6d5b10426284f506557f66181b36
17 | base_revision: b0850beeb25f6d5b10426284f506557f66181b36
18 | - platform: ios
19 | create_revision: b0850beeb25f6d5b10426284f506557f66181b36
20 | base_revision: b0850beeb25f6d5b10426284f506557f66181b36
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/examples/configurable_widget/README.md:
--------------------------------------------------------------------------------
1 | # configurable_widget
2 |
3 | A new Flutter project.
4 |
--------------------------------------------------------------------------------
/examples/configurable_widget/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/AppIntent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppIntent.swift
3 | // ConfigurableWidget
4 | //
5 | // Created by Anton Borries on 23.10.24.
6 | //
7 |
8 | import AppIntents
9 | import WidgetKit
10 |
11 | @available(iOS 17.0, *)
12 | struct ConfigurationAppIntent: WidgetConfigurationIntent {
13 | static var title: LocalizedStringResource = "Configuration"
14 | static var description = IntentDescription("This is an example widget.")
15 |
16 | // An example simple parameter
17 | @Parameter(title: "Name", default: "World")
18 | var name: String
19 |
20 | @Parameter(title: "Punctuation")
21 | var punctuation: PunctuationEntity
22 | }
23 |
24 | // Make Entity Codable so home_widget
25 | // That way home_widget can best extract the values from a configuration
26 | @available(iOS 17.0, *)
27 | struct PunctuationEntity: AppEntity, Codable {
28 | let id: String
29 |
30 | static var typeDisplayRepresentation: TypeDisplayRepresentation = "Punctuation"
31 | static var defaultQuery = PunctuationQuery()
32 |
33 | var displayRepresentation: DisplayRepresentation {
34 | DisplayRepresentation(title: "\(id)")
35 | }
36 | }
37 |
38 | @available(iOS 17.0, *)
39 | struct PunctuationQuery: EntityQuery {
40 |
41 | func punctuations() -> [PunctuationEntity] {
42 | let userDefaults = UserDefaults(suiteName: "group.es.antonborri.configurableWidget")
43 |
44 | do {
45 | let jsonPunctuations = (userDefaults?.string(forKey: "punctuations") ?? "[\"!\"]").data(
46 | using: .utf8)!
47 | let stringArray = try JSONDecoder().decode([String].self, from: jsonPunctuations)
48 | return stringArray.map { punctuation in
49 | PunctuationEntity(id: punctuation)
50 |
51 | }
52 | } catch {
53 | return [PunctuationEntity(id: "!")]
54 | }
55 |
56 | }
57 |
58 | func entities(for identifiers: [PunctuationEntity.ID]) async throws -> [PunctuationEntity] {
59 | let results = punctuations().filter { identifiers.contains($0.id) }
60 | return results
61 | }
62 |
63 | func suggestedEntities() async throws -> [PunctuationEntity] {
64 | return punctuations()
65 | }
66 |
67 | func defaultResult() async -> PunctuationEntity? {
68 | try? await suggestedEntities().first
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | }
8 | ],
9 | "info" : {
10 | "author" : "xcode",
11 | "version" : 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/ConfigurableWidget.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConfigurableWidget.swift
3 | // ConfigurableWidget
4 | //
5 |
6 | import SwiftUI
7 | import WidgetKit
8 |
9 | @available(iOS 17.0, *)
10 | struct Provider: AppIntentTimelineProvider {
11 | func placeholder(in context: Context) -> SimpleEntry {
12 | SimpleEntry(date: Date(), name: "World", punctuation: "!")
13 | }
14 |
15 | func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry
16 | {
17 | SimpleEntry(date: Date(), name: configuration.name, punctuation: configuration.punctuation.id)
18 | }
19 |
20 | func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<
21 | SimpleEntry
22 | > {
23 | var entries: [SimpleEntry] = []
24 |
25 | // Generate a timeline consisting of five entries an hour apart, starting from the current date.
26 | let currentDate = Date()
27 | for hourOffset in 0..<5 {
28 | let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
29 | let entry = SimpleEntry(
30 | date: entryDate, name: configuration.name, punctuation: configuration.punctuation.id)
31 | entries.append(entry)
32 | }
33 |
34 | return Timeline(entries: entries, policy: .atEnd)
35 | }
36 | }
37 |
38 | struct IntentProvider: IntentTimelineProvider {
39 | typealias Entry = SimpleEntry
40 |
41 | typealias Intent = GreetingIntentIntent
42 |
43 | func placeholder(in context: Context) -> SimpleEntry {
44 | SimpleEntry(date: Date(), name: "World")
45 | }
46 |
47 | func getSnapshot(
48 | for configuration: GreetingIntentIntent, in context: Context,
49 | completion: @escaping (SimpleEntry) -> Void
50 | ) {
51 | completion(SimpleEntry(date: Date(), name: configuration.Name))
52 | }
53 |
54 | func getTimeline(
55 | for configuration: GreetingIntentIntent, in context: Context,
56 | completion: @escaping (Timeline) -> Void
57 | ) {
58 | var entries: [SimpleEntry] = []
59 |
60 | // Generate a timeline consisting of five entries an hour apart, starting from the current date.
61 | let currentDate = Date()
62 | for hourOffset in 0..<5 {
63 | let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
64 | let entry = SimpleEntry(
65 | date: entryDate, name: configuration.Name,
66 | punctuation: configuration.Punctuation?.identifier)
67 | entries.append(entry)
68 | }
69 |
70 | completion(Timeline(entries: entries, policy: .atEnd))
71 | }
72 | }
73 |
74 | struct SimpleEntry: TimelineEntry {
75 | let date: Date
76 | let name: String?
77 | var punctuation: String?
78 | }
79 |
80 | struct ConfigurableWidgetEntryView: View {
81 | var entry: SimpleEntry
82 |
83 | var body: some View {
84 | VStack {
85 | Text("Hello")
86 | if let name = entry.name {
87 | Text(name)
88 | }
89 | if let punctuation = entry.punctuation {
90 | Text(punctuation)
91 | }
92 | }
93 | }
94 | }
95 |
96 | struct ConfigurableWidget: Widget {
97 | let kind: String = "ConfigurableWidget"
98 |
99 | var body: some WidgetConfiguration {
100 | if #available(iOS 17.0, *) {
101 | return AppIntentConfiguration(
102 | kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()
103 | ) {
104 | entry in
105 | ConfigurableWidgetEntryView(entry: entry)
106 | .containerBackground(.fill.tertiary, for: .widget)
107 | }
108 | } else {
109 | return IntentConfiguration(
110 | kind: kind,
111 | intent: GreetingIntentIntent.self,
112 | provider: IntentProvider()
113 | ) { entry in
114 | ConfigurableWidgetEntryView(entry: entry)
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/ConfigurableWidgetBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConfigurableWidgetBundle.swift
3 | // ConfigurableWidget
4 | //
5 | // Created by Anton Borries on 23.10.24.
6 | //
7 |
8 | import SwiftUI
9 | import WidgetKit
10 |
11 | @main
12 | struct ConfigurableWidgetBundle: WidgetBundle {
13 | var body: some Widget {
14 | ConfigurableWidget()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidget/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionPointIdentifier
8 | com.apple.widgetkit-extension
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/ConfigurableWidgetExtension.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.es.antonborri.configurableWidget
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '12.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/PunctuationIntent/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionAttributes
8 |
9 | IntentsRestrictedWhileLocked
10 |
11 | IntentsSupported
12 |
13 | GreetingIntentIntent
14 |
15 |
16 | NSExtensionPointIdentifier
17 | com.apple.intents-service
18 | NSExtensionPrincipalClass
19 | $(PRODUCT_MODULE_NAME).IntentHandler
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/PunctuationIntent/IntentHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntentHandler.swift
3 | // PunctuationIntent
4 | //
5 | // Created by Anton Borries on 16.02.25.
6 | //
7 |
8 | import Intents
9 |
10 | class IntentHandler: INExtension, GreetingIntentIntentHandling {
11 |
12 | func providePunctuationOptionsCollection(for intent: GreetingIntentIntent) async throws
13 | -> INObjectCollection
14 | {
15 | let userDefaults = UserDefaults(suiteName: "group.es.antonborri.configurableWidget")
16 |
17 | do {
18 | let jsonPunctuations = (userDefaults?.string(forKey: "punctuations") ?? "[\"!\"]").data(
19 | using: .utf8)!
20 | let stringArray = try JSONDecoder().decode([String].self, from: jsonPunctuations)
21 | let items = stringArray.map { punctuation in
22 | Punctuation(identifier: punctuation, display: punctuation)
23 | }
24 | return INObjectCollection(items: items)
25 |
26 | } catch {
27 | return INObjectCollection(items: [Punctuation(identifier: "!", display: "!")])
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/PunctuationIntent/PunctuationIntent.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.es.antonborri.configurableWidget
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import home_widget
4 |
5 | @main
6 | @objc class AppDelegate: FlutterAppDelegate {
7 | override func application(
8 | _ application: UIApplication,
9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
10 | ) -> Bool {
11 | GeneratedPluginRegistrant.register(with: self)
12 | if #available(iOS 17.0, *) {
13 | HomeWidgetPlugin.setConfigurationLookup(to: [
14 | "ConfigurableWidget": ConfigurationAppIntent.self
15 | ])
16 | }
17 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ABausG/home_widget/404bac018012b5466fc939fa3cc6cee87d1c06d6/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CADisableMinimumFrameDurationOnPhone
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleDisplayName
10 | Configurable Widget
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | configurable_widget
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | $(FLUTTER_BUILD_NAME)
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | $(FLUTTER_BUILD_NUMBER)
27 | LSRequiresIPhoneOS
28 |
29 | NSUserActivityTypes
30 |
31 | GreetingIntentIntent
32 |
33 | UIApplicationSupportsIndirectInputEvents
34 |
35 | UILaunchStoryboardName
36 | LaunchScreen
37 | UIMainStoryboardFile
38 | Main
39 | UISupportedInterfaceOrientations
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationLandscapeLeft
43 | UIInterfaceOrientationLandscapeRight
44 |
45 | UISupportedInterfaceOrientations~ipad
46 |
47 | UIInterfaceOrientationPortrait
48 | UIInterfaceOrientationPortraitUpsideDown
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/examples/configurable_widget/ios/Runner/Runner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.es.antonborri.configurableWidget
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/configurable_widget/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:home_widget/home_widget.dart';
5 |
6 | void main() {
7 | WidgetsFlutterBinding.ensureInitialized();
8 | _initPunctuations();
9 | runApp(const MainApp());
10 | }
11 |
12 | /// Send a List of possible punctuations to the widget.
13 | Future _initPunctuations() async {
14 | // Needed for communication between the app and the widget
15 | await HomeWidget.setAppGroupId('group.es.antonborri.configurableWidget');
16 | final punctuations = [
17 | '!',
18 | '!!!',
19 | '.',
20 | '?',
21 | // Wave Emoji
22 | '\u{1F44B}',
23 | ];
24 | // Save the punctuations to the widget
25 | await HomeWidget.saveWidgetData(
26 | 'punctuations',
27 | jsonEncode(punctuations),
28 | );
29 | }
30 |
31 | class MainApp extends StatefulWidget {
32 | const MainApp({super.key});
33 |
34 | @override
35 | State createState() => _MainAppState();
36 | }
37 |
38 | class _MainAppState extends State {
39 | List