Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
62bd1d5
Fix: await Permission.location.request() returns PermissionStatus.den…
HasanAlqaisi Nov 19, 2025
b915778
feat(apple): add Swift Package Manager support (#1523)
TheoGermain May 29, 2026
7c3add9
Update version to 12.0.2
mvanbeusekom May 29, 2026
6be38d4
fix typo in README about the compileSdkVersion (#1472)
assanbayg Jun 1, 2026
db4e61d
docs: fix completeSdkVersion typo to compileSdkVersion (#1494)
harshitsaini98 Jun 1, 2026
83b6f34
Improved the iOS Setup section in permission_handler/README.md (#1488)
Hemo-Sul Jun 1, 2026
977f72c
Rewrite copyleft code from stackoverflow
mvanbeusekom Jun 1, 2026
2e46a3f
Bump permission_handler_apple to 9.4.9
mvanbeusekom Jun 1, 2026
7ab3962
Bump permission_handler to 12.0.3
mvanbeusekom Jun 1, 2026
bfa56cf
Bump permission_handler_apple to 9.4.9
mvanbeusekom Jun 1, 2026
6bf322b
Changed Info.plist lookup (#1542)
olekeke999 Jun 12, 2026
cf9d9fa
Android `ACCESS_LOCAL_NETWORK`, package monorepo `pubspec.yaml` (#1541)
zeyus Jul 31, 2026
d347e5d
Removed obsolete and conflicting packageName attribute
mvanbeusekom Jul 31, 2026
e503c1c
Update version to reflect new feature
mvanbeusekom Jul 31, 2026
96bf5cc
Update version to reflect new feature
mvanbeusekom Jul 31, 2026
7b36a22
Fix version to align with current production version
mvanbeusekom Jul 31, 2026
1655dee
Fix dependency in android example app
mvanbeusekom Jul 31, 2026
363bb40
Update version to reflect breaking change in Android
mvanbeusekom Jul 31, 2026
0d9e6ea
Fixes error handling in web.delegate
mvanbeusekom Aug 1, 2026
ac58849
Fix web release crash: use Dart is checks for DOMException in web_del…
prkay Aug 1, 2026
b7d387a
Fix SPM Info.plist discovery for flavored and multi-configuration app…
Pachebel Aug 10, 2026
c563444
Add opt-in per-flavor permissions for Swift Package Manager builds (2…
Pachebel Aug 10, 2026
0501b21
Fix and document the Swift Package Manager section of the main README…
Pachebel Aug 11, 2026
6605dbb
Updates version number
mvanbeusekom Aug 11, 2026
8c64b00
Fix/android ask every time permanently denied (#1559)
TetrixGauss Sep 4, 2026
4d6eda7
docs: clarify which Info.plist key to delete (#1013) (#1560)
AzazelSensei Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions .github/workflows/permission_handler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
# TODO(mvanbeusekom): Manually set to macOS 15 to support Xcode 16 and iOS 18 SDKs.
# Currently `macos-latest` is based on macOS 14 and doesn't support iOS 18 SDK. This
# should be moved back to `macos-latest` when GitHub Actions images are updated.
runs-on: macos-15
runs-on: macos-15

env:
source-directory: ./permission_handler
Expand All @@ -42,7 +42,6 @@ jobs:
with:
distribution: "temurin" # See 'Supported distributions' for available options
java-version: "17"

# Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v2
with:
Expand All @@ -62,18 +61,7 @@ jobs:
- name: Run Flutter Analyzer
run: flutter analyze
working-directory: ${{env.source-directory}}

# Build Android version of the example App
- name: Run Android build
run: flutter build apk --release
working-directory: ${{env.example-directory}}

# Build iOS version of the example App
- name: Run iOS build
run: flutter build ios --release --no-codesign
working-directory: ${{env.example-directory}}

# Run all unit-tests with code coverage
# Run all unit-tests with code coverage
- name: Run unit tests
run: flutter test --coverage
working-directory: ${{env.source-directory}}
Expand All @@ -85,3 +73,13 @@ jobs:
file: ${{env.source-directory}}/coverage/lcov.info # optional
flags: unittests # optional
name: permission_handler # optional

# Build Android version of the example App
- name: Run Android build
run: flutter build apk --release
working-directory: ${{env.example-directory}}

# Build iOS version of the example App
- name: Run iOS build
run: flutter build ios --release --no-codesign
working-directory: ${{env.example-directory}}
22 changes: 10 additions & 12 deletions .github/workflows/permission_handler_android.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ name: permission_handler_android
# events but only for the main branch
on:
push:
branches: [ main ]
branches: [main]
paths:
- 'permission_handler_android/**'
- '.github/workflows/permission_handler_android.yaml'
- "permission_handler_android/**"
- ".github/workflows/permission_handler_android.yaml"
pull_request:
branches: [ main ]
branches: [main]
paths:
- 'permission_handler_android/**'
- '.github/workflows/permission_handler_android.yaml'
- "permission_handler_android/**"
- ".github/workflows/permission_handler_android.yaml"

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
Expand All @@ -26,7 +26,7 @@ jobs:

env:
source-directory: ./permission_handler_android
example-directory: ./permission_handler_android/example
example-directory: ./permission_handler_android/example

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
Expand All @@ -36,13 +36,12 @@ jobs:
# Make sure JAVA version 17 is installed on build agent.
- uses: actions/setup-java@v3
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'

distribution: "temurin" # See 'Supported distributions' for available options
java-version: "17"
# Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
channel: "stable"

# Download all Flutter packages
- name: Download dependencies
Expand All @@ -63,4 +62,3 @@ jobs:
- name: Run Android build
run: flutter build apk --release
working-directory: ${{env.example-directory}}

150 changes: 148 additions & 2 deletions .github/workflows/permission_handler_apple.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,153 @@ jobs:
run: flutter analyze
working-directory: ${{env.source-directory}}

# Build iOS version of the example App
# Build iOS version of the example App.
#
# The example resolves this plugin as a Swift package (the Podfile only
# covers its remaining CocoaPods dependencies), so the "Verify
# permission_handler flavor" build phase is active and `strict: true`
# demands a selection before a Release build can run. `select` also
# generates ios/Flutter/permission_handler.resolved.json from
# permission_handler.yaml — neither it nor the selection file is
# committed, so every CI run has to make its own.
- name: Run iOS build
run: flutter build ios --no-codesign --release
working-directory: ${{env.example-directory}}
run: |
set -euo pipefail
dart run permission_handler_apple:select release
flutter build ios --no-codesign --release

# Guard the Swift Package Manager permission resolution.
#
# Package.swift turns the usage description keys of the host app's
# Info.plist into PERMISSION_* macros. When that breaks, every macro
# silently falls back to 0 and all permissions are compiled out, so assert
# on the resolved manifest rather than on the build succeeding.
#
# The example declares two flavors over two Info.plist files that differ by
# exactly one key: `debug` (Info-Debug.plist, the build-configuration
# specific layout reported in issue #1548) has no contacts entry,
# `release` (Info.plist) does. That single difference is what proves both
# that a flavor cannot inherit another flavor's permissions and, on the
# legacy path, that both plists were discovered and merged.
- name: Verify SPM permission resolution
working-directory: ${{env.example-directory}}
run: |
set -euo pipefail
flutter config --enable-swift-package-manager
flutter build ios --config-only --debug --no-codesign

# Resolve the manifest under a given environment, capturing the macros
# (stdout) and the PERMISSION_HANDLER_VERBOSE diagnostics (stderr).
resolve() { # <name> <VAR=value>...
local name="$1"; shift
rm -rf ~/Library/Caches/org.swift.swiftpm/manifests
env PERMISSION_HANDLER_VERBOSE=1 "$@" swift package --manifest-cache none \
--package-path ios/Flutter/ephemeral/Packages/.packages/permission_handler_apple \
dump-package > "${RUNNER_TEMP}/${name}.json" 2> "${RUNNER_TEMP}/${name}.log"
echo "--- ${name} ---"
cat "${RUNNER_TEMP}/${name}.log"
}

expect() { # <name> <macro=value>...
local name="$1"; shift
for macro in "$@"; do
grep -qF "${macro}" "${RUNNER_TEMP}/${name}.json" || {
echo "::error::[${name}] expected ${macro} in the resolved manifest"
grep -o 'PERMISSION_[A-Z_]*=[01]' "${RUNNER_TEMP}/${name}.json" | sort -u
exit 1
}
done
}

expect_log() { # <name> <fixed string> <message>
grep -qF "$2" "${RUNNER_TEMP}/$1.log" || { echo "::error::[$1] $3"; exit 1; }
}

# Without a permission_handler.yaml the pre-flavor behaviour has to be
# unchanged: discover every Info.plist and merge them. PERMISSION_CONTACTS
# can only be 1 if both plists were found, which is what makes this
# assert on the discovery rather than on the example's default plist.
resolve legacy PERMISSION_HANDLER_CONFIG=/nonexistent/permission_handler.yaml
expect_log legacy 'Runner/Info.plist' \
'ios/Runner/Info.plist was not discovered'
expect_log legacy 'Runner/Info-Debug.plist' \
'ios/Runner/Info-Debug.plist was not discovered — INFOPLIST_FILE parsing is broken'
expect_log legacy 'NSContactsUsageDescription' \
'the divergence warning did not fire — the plists were not merged'
expect legacy PERMISSION_CONTACTS=1 PERMISSION_CAMERA=1 PERMISSION_MICROPHONE=1 \
PERMISSION_PHOTOS=1 PERMISSION_LOCATION=1

# The debug flavor must not see the release flavor's contacts entry.
resolve debug PERMISSION_HANDLER_FLAVOR=debug
expect debug PERMISSION_CONTACTS=0 PERMISSION_CAMERA=1 PERMISSION_MICROPHONE=1

# ...and the release flavor must see it.
resolve release PERMISSION_HANDLER_FLAVOR=release
expect release PERMISSION_CONTACTS=1 PERMISSION_CAMERA=1 PERMISSION_MICROPHONE=1

# With `strict: true` an unresolved flavor compiles nothing in,
# rather than falling back to the union of every flavor. The earlier
# build step recorded a selection, so drop it first — otherwise the
# manifest resolves that flavor and this asserts nothing. The
# generated resolved.json stays; only the selection is missing.
rm -f ios/Flutter/permission_handler.selected
resolve strict
expect strict PERMISSION_CONTACTS=0 PERMISSION_CAMERA=0 PERMISSION_MICROPHONE=0

# Editing permission_handler.yaml without re-running `select` must not
# build with the stale translation: everything compiles out and the
# manifest says to re-run select.
touch permission_handler.yaml
resolve stale PERMISSION_HANDLER_FLAVOR=release
expect stale PERMISSION_CONTACTS=0 PERMISSION_CAMERA=0 PERMISSION_MICROPHONE=0
expect_log stale 'modified after its generated translation' \
'the staleness guard did not fire'

# An app target whose INFOPLIST_FILE is built from a variable this manifest
# does not expand, next to an extension carrying Xcode's stock
# `GENERATE_INFOPLIST_FILE = YES`. Neither yields a usable path, so the
# scan of `ios/` has to take over; a settings hit that resolves to nothing
# must not suppress it. Built here rather than committed, because it is a
# project layout the example cannot also be.
- name: Verify SPM detection falls back to scanning
run: |
set -euo pipefail
app="${RUNNER_TEMP}/fallback-app"
rm -rf "${app}"
mkdir -p "${app}/ios/Extension.xcodeproj" "${app}/ios/Runner"
touch "${app}/pubspec.yaml"
cp "${{env.example-directory}}/ios/Runner/Info.plist" "${app}/ios/Runner/Info.plist"
printf 'GENERATE_INFOPLIST_FILE = YES;\nINFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";\n' \
> "${app}/ios/Extension.xcodeproj/project.pbxproj"

cd "${app}"
rm -rf ~/Library/Caches/org.swift.swiftpm/manifests
PERMISSION_HANDLER_VERBOSE=1 swift package --manifest-cache none \
--package-path "${GITHUB_WORKSPACE}/permission_handler_apple/ios/permission_handler_apple" \
dump-package > "${RUNNER_TEMP}/fallback.json" 2> "${RUNNER_TEMP}/fallback.log"
cat "${RUNNER_TEMP}/fallback.log"

grep -qF 'PERMISSION_CAMERA=1' "${RUNNER_TEMP}/fallback.json" || {
echo "::error::the scan fallback did not run — an unresolvable INFOPLIST_FILE suppressed it"
exit 1
}

# The build phase that catches a stale selection is the only check that
# runs on every build, so make sure it actually fails.
- name: Verify flavor mismatch fails the build
working-directory: ${{env.example-directory}}
run: |
set -euo pipefail
dart run permission_handler_apple:select release
if xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner \
-configuration Debug -sdk iphonesimulator \
-derivedDataPath "${RUNNER_TEMP}/dd" build > "${RUNNER_TEMP}/mismatch.log" 2>&1; then
echo "::error::a Debug build with the release flavor selected should have failed"
exit 1
fi
grep -q 'needs the "debug" permission flavor' "${RUNNER_TEMP}/mismatch.log" || {
echo "::error::build failed, but not with the flavor mismatch error"
tail -40 "${RUNNER_TEMP}/mismatch.log"
exit 1
}
27 changes: 14 additions & 13 deletions .github/workflows/permission_handler_platform_interface.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ name: permission_handler_platform_interface
# events but only for the main branch
on:
push:
branches: [ main ]
branches: [main]
paths:
- 'permission_handler_platform_interface/**'
- '.github/workflows/permission_handler_platform_interface.yaml'
- "permission_handler_platform_interface/**"
- ".github/workflows/permission_handler_platform_interface.yaml"
pull_request:
branches: [ main ]
branches: [main]
paths:
- 'permission_handler_platform_interface/**'
- '.github/workflows/permission_handler_platform_interface.yaml'
- "permission_handler_platform_interface/**"
- ".github/workflows/permission_handler_platform_interface.yaml"

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
Expand All @@ -25,17 +25,17 @@ jobs:
runs-on: ubuntu-latest

env:
source-directory: ./permission_handler_platform_interface
source-directory: ./permission_handler_platform_interface

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

# Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
channel: "stable"

# Download all Flutter packages
- name: Download dependencies
Expand All @@ -46,20 +46,21 @@ jobs:
- name: Run Dart Format
run: dart format --set-exit-if-changed .
working-directory: ${{env.source-directory}}

# Run Flutter Analyzer
- name: Run Flutter Analyzer
run: flutter analyze
working-directory: ${{env.source-directory}}

# Run all unit-tests with code coverage
- name: Run unit tests
run: flutter test --coverage
working-directory: ${{env.source-directory}}

# Upload code coverage information
- uses: codecov/codecov-action@v1
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ${{env.source-directory}}/coverage/lcov.info # optional
name: permission_handler_platform_interface (Platform Interface Package) # optional
fail_ci_if_error: true
flags: unittests
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
.project
.svn/
bin/
# ...except packages that ship an executable, which pub requires to live in bin/.
!permission_handler_apple/bin/
migrate_working_dir/

# IntelliJ related
Expand Down
Loading
Loading