Skip to content

Changed Info.plist lookup#1542

Merged
mvanbeusekom merged 5 commits into
Baseflow:mainfrom
olekeke999:SPM-infoplist-lookup
Jun 12, 2026
Merged

Changed Info.plist lookup#1542
mvanbeusekom merged 5 commits into
Baseflow:mainfrom
olekeke999:SPM-infoplist-lookup

Conversation

@olekeke999

@olekeke999 olekeke999 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

I have flutter 3.44 with global SPM enabled. I noticed on my project that all permissions pernamentlyDenied. I've read similar issues and understood that it's related to lookup of Info.plist permissions.
I tried to use permissions_handler_apple/example ios project, migrated it to SPM and permissions were pernamentlyDenided as well, only if I used launchctl "launchctl setenv PERMISSION_CAMERA 1" it worked.
So I did code changes to improve Info.plist lookup and it helped on both permissions_handler_apple/example and as dependency overwrite in my monorepo project.

  • Package.swift Info.plist lookup fix
  • migrated iOS permissions_handler_apple/example from Pods to SPM

Pre-launch Checklist

  • [+] I made sure the project builds.
  • [+] I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • [+] I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is does not need version changes.
  • [+] I updated CHANGELOG.md to add a description of the change.
  • [-] I updated/added relevant documentation (doc comments with ///).
  • [+] I rebased onto main.
  • [-] I added new tests to check the change I am making, or this PR does not need tests.
  • [-] I made sure all existing and new tests are passing.
  • [-] I ran dart format . and committed any changes.
  • [-] I ran flutter analyze and fixed any errors.

@mvanbeusekom

Copy link
Copy Markdown
Member

Hi @TheoGermain, would you mind helping out and doing a review on this PR? Since you added the initial code I feel your input on this could be very valuable.

@TheoGermain

Copy link
Copy Markdown
Contributor

Hey, thanks for digging into this and providing a reproduction with the example project. The root cause you identified is correct.

With global SPM enabled in Flutter 3.44+, the #file path during manifest evaluation no longer points into the project tree. It ends up somewhere in DerivedData or the global SPM cache, so walking up from there never reaches Runner/Info.plist. The fact that launchctl setenv PERMISSION_CAMERA 1 bypasses the issue confirms exactly this: the env var path works fine, the plist lookup just never finds the file.

Adding FileManager.default.currentDirectoryPath as a second search root is the right instinct, since the working directory during manifest evaluation often stays anchored to the project. That part of the fix makes sense to me.

A few things I would want to look at before merging though.

The recursive subdirectory scan in appendInfoPlistCandidates worries me for monorepo setups. If someone has multiple apps under one root (a common Flutter monorepo pattern), that scan could pick up the wrong Info.plist and silently enable the wrong set of permissions at compile time.

What I would suggest instead is keeping the walk-up approach but using pubspec.yaml as a reliable Flutter project-root anchor. At each level, check whether pubspec.yaml exists alongside ios/Runner/Info.plist. Every Flutter app has exactly one pubspec.yaml at its root, and a melos workspace root may also have one but will never have ios/Runner/Info.plist next to it. This makes the match unambiguous even in monorepos.

Something along these lines:

func findInfoPlist() -> [String: Any] {
    let fm = FileManager.default
    let searchRoots: [URL] = [
        URL(fileURLWithPath: #file).deletingLastPathComponent(),
        URL(fileURLWithPath: fm.currentDirectoryPath),
    ]

    var visited = Set<String>()

    for root in searchRoots {
        var dir = root
        for _ in 0..<12 {
            let key = dir.resolvingSymlinksInPath().path
            guard visited.insert(key).inserted else { break }

            let plistURL = dir.appendingPathComponent("ios/Runner/Info.plist")
            if fm.fileExists(atPath: dir.appendingPathComponent("pubspec.yaml").path),
               let plist = NSDictionary(contentsOf: plistURL) as? [String: Any] {
                return plist
            }

            dir = dir.deletingLastPathComponent()
        }
    }
    return [:]
}

This covers both the standard SPM case and global SPM, deduplicates paths so the two roots do not overlap, and avoids any recursive directory scanning.

The FlutterFramework dependency added to the package target is also something I would want to understand better. The current package does not declare that dependency and resolves fine in normal SPM mode, so I am not sure what it brings here and I would want to make sure it does not break setups where that package is not available at that relative path.

Finally, the example migration from CocoaPods to SPM is a great validation step, but it is a fairly significant change on its own. It might be cleaner to split it into a separate PR so the core plist lookup fix can be reviewed and merged independently.

Would you be open to a narrower version of the patch focused on the findInfoPlist change? Happy to iterate on it with you.

@olekeke999

olekeke999 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@TheoGermain , thank you for detailed response.
will take a look and return with update.

The FlutterFramework dependency added

this is new requirement from Flutter 3.41. - https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-plugin-authors#:~:text=New%20in%20Flutter%203.41!%20Add%20the%20FlutterFramework
without it, there is red warning during app building.

@TheoGermain

Copy link
Copy Markdown
Contributor

Good to know about FlutterFramework, I missed that change in 3.41. Thanks for the pointer. Looking forward to the updated patch.

@olekeke999

Copy link
Copy Markdown
Contributor Author

@TheoGermain I updated the PR. It was a good idea with finding pubspec.yaml.

removed FlutterFramework from the dependencies, because it requires us to bump flutter restrictions in the pubspec.yaml to flutter: ">=3.41.0". However, I found it works on my side (3.44.0) without setting this restriction. Just showing warning. Fine for now.

during this fix, I tried to test it in three projects - example, freshly created app and my main app (monorepo with a lot of local feature packages).

flutter resolves package into path:
./ios/Flutter/ephemeral/Packages/.packages/permission_handler_apple/Package.swift
and it looks up and founs pubspec.yaml.

Maybe using current dir is not even needed here, however, I decided to leave it as a second chance.

All 3 apps worked correctly. Then I removed in this PR changes related to SPM for permission_handler_apple/example app.

I haven't tested older versions of flutter.

@TheoGermain

Copy link
Copy Markdown
Contributor

Thanks for the update, the pubspec.yaml anchor approach looks solid and I'm glad it worked across your three test environments.

On the FlutterFramework point, I want to make sure we're clear on the trade-off before merging. Removing it is actually the right call here, but not just because it works without it. The real reason is that pubspec.yaml constraints apply to all users regardless of their iOS integration. If we bumped flutter to >=3.41.0, we would also block every CocoaPods user still on Flutter 3.3 to 3.40, even though they have nothing to do with Package.swift and are completely unaffected by this change. That would be an unnecessary breakage for a lot of people.

So yes, SPM users on 3.41 and above will see a build warning, and that is a known downside. But it is a better trade-off than breaking CocoaPods users on older Flutter versions.

That said, I would rather we document this explicitly in the CHANGELOG instead of leaving it implicit. Something like: "FlutterFramework is intentionally not declared in Package.swift. Adding it would require a flutter >=3.41.0 constraint that would unnecessarily affect CocoaPods users. SPM users on Flutter 3.41+ may see a related build warning."

Would you be okay adding that? Otherwise the fix looks good to me.

@olekeke999

Copy link
Copy Markdown
Contributor Author

@TheoGermain thanks. Sure, I will update the Changelog.
regarding cocoapods users. As this plugin doesn't use any 3rd party dependencies in the podspec it should be fine even after cocoapods became read only.
but if for some reason any new version of flutter start breaking without adding the FlutterFramework, we'll need to add this change.

@olekeke999

Copy link
Copy Markdown
Contributor Author

updated CHANGELOG.md

@mvanbeusekom mvanbeusekom merged commit 64039de into Baseflow:main Jun 12, 2026
1 check passed
@mvanbeusekom

Copy link
Copy Markdown
Member

Thank you @olekeke999 and @TheoGermain for putting this together. Awesome work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants