Repository navigation
Support privacy manifests for non-plugin packages calling required reason APIs directly via FFI #147186
Description
Activity
- addedtoolAffects the "flutter" command-line tool. See also t: labels.Affects the "flutter" command-line tool. See also t: labels.a: buildBuilding flutter applications with the toolBuilding flutter applications with the toolfyi-ecosystemFor the attention of Ecosystem teamFor the attention of Ecosystem teamteam-iosOwned by iOS platform teamOwned by iOS platform team
on Apr 22, 2024 We'd need a way for package developers to declare a manifest that we would bundle; probably a
flutter:sub-entry inpubspec.yamlis the best option?It's a big magical, but we could also have some known path (in
lib/?) where, if there's aPrivacyInfo.xcprivacy., the tooling automatically bundles it up. Kind of howAppFrameworkInfo.plistis used as theApp.frameworkInfo.plist:flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart
Lines 519 to 522 in 140edb9
flutterProject.ios.appFrameworkInfoPlist .copySync(environment.outputDir .childDirectory('App.framework') .childFile('Info.plist').path); cc @dcharkes
Reacted by Daco HarkesOne question to answer is whether any other embedders than Flutter would ever need to include such privacy manifest. If the answer is yes, then
hook/build.dartshould output it as meta-data to theNativeCodeAsset. That way a package with a build hook would work in such other embedder as well. If the answer is no, we can build a Flutter-specific solution.Currently, I am not aware of any Dart embedders other than Flutter that end up being published in the Apple App store. Are you aware of any @mit-mit @mariamhas @mraleph?
Duplicate issue:
Duplicate issue
It's not a duplicate issue; this one is about the case where someone writes a pure Dart package that directly makes FFI calls to a required reason API.
then
hook/build.dartshould output it as meta-data to theNativeCodeAsset.In this scenario there is no
hook/build.dart, nor any native code assets.(Adjusting title to try to make the distinction clearer.)
- changed the title
[-]Support privacy manifests for non-plugin packages using FFI[/-][+]Support privacy manifests for non-plugin packages calling required reason APIs directly via FFI[/+]on Apr 23, 2024 Ah, interesting!
So these would be using
DynamicLibrary.process.lookupto access a system API. Do I understand this correctly?We could consider saying users should use
@Nativeinstead and report aNativeCodeAssetwithLookupInProcessfrom theirbuild.dartwhen addressing #140966. However, since native assets are currently in experimental, that wouldn't solve it for users currently usingDynamicLibrary.process.lookupwithout the experiment.So these would be using
DynamicLibrary.process.lookupto access a system API. Do I understand this correctly?Yes (probably via
ffigenor one of the related tools).We could consider saying users should use
@Nativeinstead and report aNativeCodeAssetwithLookupInProcessfrom theirbuild.dartOh, I guess
build.dartdoesn't actually require building anything, right? So someone could have have a native asset package whose only native asset was the privacy manifest bundle, and no native code?Although it's not clear to me how we would wire to get the right output. In the case envisioned in #140966, my understanding is that we would end up with a
TheNativeCodeICompiled.framework, containing a privacy manifest for the RRAPI calls made by that code, which would work out. In this issue's scenario though, the RRAPI calls are (for a Flutter build) inApp.framework, so the corresponding privacy manifest must be inApp.frameworkfor the App Store validator to accept it. But it doesn't seem likebuild.dartwould have a way to make that happen.Or did you mean that we should recommend that nobody ever call, e.g.,
statvia FFI, and if they really want to callstatthey should instead write a trivialmy_statand package it via native assets, and call that? If so, forcing people to add a native build step to their package for basically no reason doesn't seem desireable.So these would be using
DynamicLibrary.process.lookupto access a system API. Do I understand this correctly?Yes (probably via
ffigenor one of the related tools).We could consider saying users should use
@Nativeinstead and report aNativeCodeAssetwithLookupInProcessfrom theirbuild.dartOh, I guess
build.dartdoesn't actually require building anything, right? So someone could have have a native asset package whose only native asset was the privacy manifest bundle, and no native code?yes. 👍
Although it's not clear to me how we would wire to get the right output. In the case envisioned in #140966, my understanding is that we would end up with a
TheNativeCodeICompiled.framework, containing a privacy manifest for the RRAPI calls made by that code, which would work out. In this issue's scenario though, the RRAPI calls are (for a Flutter build) inApp.framework, so the corresponding privacy manifest must be inApp.frameworkfor the App Store validator to accept it. But it doesn't seem likebuild.dartwould have a way to make that happen.Well,
flutter_toolsis the consumer ofbuild.darts output.build.dartonly outputs.dylibs and meta data. Flutter Tools can decide whatever it wants to do. Flutter tools is the one taking the dylib and making it a framework.If
App.frameworkis the right place, we should thread the privacy manifests from all individualNativeCodeAssets to theApp.frameworkinstead of in their individual frameworks.Or did you mean that we should recommend that nobody ever call, e.g.,
statvia FFI, and if they really want to callstatthey should instead write a trivialmy_statand package it via native assets, and call that? If so, forcing people to add a native build step to their package for basically no reason doesn't seem desireable.No. I'd suggest having a
hook/build.dartwith:void main() async { await build(config, output) { output.addAsset( NativeCodeAsset( package: 'my_package', name: 'stat.dart', linkMode: LookupInProcess(), // Will cause `@Native` to be `DynamicLibrary.process.lookup` at runtime. os: config.targetOS, architecture: config.targetArchitecture, // privacyManifest: ..., ), ); }); }
And then the code in the package:
// package:my_package/stat.dart // Generated by FFIgen with `ffi-native:` @Native<Int Function(Pointer<Char>, Pointer<Stat>)>() int stat(Pointer<Char> pathname, Pointer<Stat> statbuf);
This would not do any native build. It's basically only some meta-data communicated back to to Flutter from
hook/build.dart.Or did you mean that we should recommend that nobody ever call, e.g.,
statvia FFI.I would then indeed recommend nobody call
statviaDynamicLibrary.process.lookup. (Both are FFI, I presume you meanDynamicLibraryAPI with FFI here.)I agree that using
build.dartwithLookupInProcess()is more ceremony thanDynamicLibrary.process.lookup. So maybe this isn't the right way to go. On the other hand, we only have to introduce one solution instead of two if we move users to the@Natives instead ofDynamicLibrary.Well,
flutter_toolsis the consumer ofbuild.darts output.build.dartonly outputs.dylibs and meta data. Flutter Tools can decide whatever it wants to do. Flutter tools is the one taking the dylib and making it a framework.Ah, okay. I had been thinking
build.dartwas going to be essentially a black box that would spit out the framework. This makes sense then.On the other hand, we only have to introduce one solution instead of two if we move users to the
@Natives instead ofDynamicLibrary.As long as we don't need to actually introduce a native compile step, I'm in favor of fewer solutions :)
Reacted by Daco Harkes- addedtriaged-ecosystemTriaged by Ecosystem teamTriaged by Ecosystem team
on Apr 23, 2024 - removedfyi-ecosystemFor the attention of Ecosystem teamFor the attention of Ecosystem teamtriaged-ecosystemTriaged by Ecosystem teamTriaged by Ecosystem team
on Apr 23, 2024 - addedP2Important issues not at the top of the work listImportant issues not at the top of the work listtriaged-iosTriaged by iOS platform teamTriaged by iOS platform team
on Apr 24, 2024
We have a privacy manifest system in place for plugins that allows plugin developers to declare required reason API usage. However, I didn't consider the case of a non-plugin, pure-Dart package that uses FFI to directly call required reason APIs; we should have a way for packages doing that to declare a manifest and have it bundled into App.framework.
We could probably do this in the Flutter tool, by having it create privacy manifest bundles in App.framework (like what Cocoapods does for static linking). We'd need a way for package developers to declare a manifest that we would bundle; probably a
flutter:sub-entry inpubspec.yamlis the best option?In the meantime, the workaround for this (hopefully very rare) case would be either: