@facilitronworks/react-native-windows-image-picker

中文文档
0.1.0-pre.0发布于 2026/07/18MITTypeScriptCommonJS零依赖近 30 天下载 4245

A native image and document picker TurboModule for React Native Windows (new architecture), backed by Windows.Storage.Pickers.FileOpenPicker.

原始使用文档
文档目录12 节
  1. Why this exists
  2. Related prior art
  3. The hard part: IInitializeWithWindow
  4. Installation
  5. Integration
  6. Usage
  7. Result shape
  8. Why files are copied
  9. API
  10. Roadmap
  11. Contributing
  12. License

@facilitronworks/react-native-windows-image-picker

A native image and document picker TurboModule for React Native Windows on the new architecture (Fabric / Composition), backed by Windows.Storage.Pickers.FileOpenPicker.

Status: pre-release (0.1.0-pre.0), not yet published to npm. The C++ implementation is extracted from a shipping production Windows app (RNW 0.83.2, Windows-on-ARM and x64) where it backs real image and file-attachment upload flows.

Build-verified. The packaged form compiles: autolinked into a consuming RNW 0.83.2 new-arch app and built clean for ARM64 Debug, producing RNWImagePicker.dll, .winmd, .lib and .pri. autolink-windows correctly emits both #include <winrt/RNWImagePicker.h> and packageProviders.Append(winrt::RNWImagePicker::ReactPackageProvider()).

Not yet verified: runtime behaviour of this project's DLL on-device (the source is production-proven, but the binary built from this project has not been exercised), x64 and Release configurations, and there is no example app or CI build yet. Wait for 0.1.0 before depending on it in production.

Building it yourself: run a NuGet restore first (msbuild -restore). Without it the CppWinRT targets never load, .idl files fall through to classic midl.exe instead of midlrt, and every namespace declaration fails with MIDL2025.

Why this exists

There is no maintained file/image picker for React Native Windows. This isn't an oversight — every upstream door has been tried and closed:

  • @react-native-documents/picker dropped Windows, and the maintainer declined to take it back: "No one has stepped up to maintain it in years. I don't think it's a good idea to add it into this repo (because it will, again, be unmaintained)."
  • React Native Windows core has no plan to ship one: "AFAIK there's no plan to expose a built-in way to access windows file pickers for RNW... you'd probably need to expose the APIs yourself, like you said, with your own Turbo Module."
  • expo-image-picker has no Windows implementation, and Expo's additional platform support covers only macOS and tvOS.
  • react-native-image-picker has had open Windows requests since 2021 and 2023, both unanswered.

RNW's own native module docs point at exactly this outcome: publish your own library when "an existing library doesn't already exist (or you don't have permission to modify it)."

If you only need document/folder picking, look at @hbannro/rn-documents-picker-windows first — it's MIT, new-arch, mirrors the @react-native-documents/picker API, and solves the HWND problem correctly. It targets RNW 0.77 and has no image-specific surface (no dimensions, base64, or image-restricted filtering), which is why this package exists separately rather than as a PR to it.

The hard part: IInitializeWithWindow

This is the trap that catches everyone, and the main reason this code is worth sharing.

On a WinAppSDK / Win32 desktop app there is no CoreWindow. A FileOpenPicker tries to parent itself to one, doesn't find it, and throws — usually surfacing as an opaque E_FAIL or a hang, with nothing pointing at the real cause. The picker must be explicitly associated with the app's top-level HWND through the classic COM interface IInitializeWithWindow:

#include <shobjidl_core.h>

auto initWithWindow = picker.as<::IInitializeWithWindow>();
initWithWindow->Initialize(ResolveHostWindow());

Two further constraints that are easy to get wrong:

  1. The pick must run on the UI thread. The dialog is modal and owned by the app window. This module hops onto the RNW dispatcher with a small ResumeOnDispatcher coroutine awaiter before creating or showing the picker.
  2. The HWND must be a real top-level window. This module prefers a handle registered once from WinMain, then falls back to GetActiveWindow() and GetForegroundWindow() — both valid fallbacks precisely because the pick already runs on the thread that owns the app window.

Installation

npm install @facilitronworks/react-native-windows-image-picker
# or: yarn add @facilitronworks/react-native-windows-image-picker

Then autolink and rebuild:

npx react-native autolink-windows
npx react-native run-windows

That is all the build wiring there is. The package ships a real windows/RNWImagePicker/RNWImagePicker.vcxproj plus a react-native.config.js declaring it as a direct Windows dependency, so autolink-windows adds the ProjectReference to your app project and emits the provider registration into your generated AutolinkedNativeModules.g.cpp. There is nothing to copy, and nothing to add to your own .vcxproj.

Requires the new architecture — <RnwNewArch>true</RnwNewArch> in your app's windows/ExperimentalFeatures.props. Developed against RNW 0.83.x.

Integration

Autolinking registers the module — the attributed REACT_MODULE is picked up by this library's own ReactPackageProvider, which calls AddAttributedModules(packageBuilder, true) on your behalf. It is then reachable from JS as NativeModules.RNWImagePicker, or through the typed wrappers in src/index.ts (see Usage).

One manual step remains: the host window. Autolinking cannot register your HWND, so this hook stays yours. Call it once from WinMain, after the app window is created:

// <winrt/RNWImagePicker.h> is already pulled in for you by AutolinkedNativeModules.g.h
winrt::RNWImagePicker::ImagePicker::SetHostWindow(reinterpret_cast<uint64_t>(hwnd));

SetHostWindow is projected as a static on an ImagePicker runtimeclass rather than exposed as a plain C++ function, because autolinking hands your app this library's WinMD projection (<winrt/RNWImagePicker.h>) but not its raw headers — and the library links as its own DLL, whose exports are just the WinRT activation entry points. The internal free function RNWImagePicker::SetHostWindow(void*) still exists for anyone vendoring the sources directly.

Why it matters: this is the one fully reliable source for the window the picker must parent to — it is captured directly from the AppWindow the RNW host created, rather than inferred. If you skip it the GetActiveWindow / GetForegroundWindow fallbacks usually work, but "usually" is not what you want behind a modal dialog.

A future version will prefer ReactCoreInjection::GetTopLevelWindowId(context.Properties().Handle()) so the WinMain hook becomes optional. The current fallback chain is the version that has actually shipped, so it is what is published here.

Usage

import {
  launchImageLibraryAsync,
  launchDocumentPickerAsync,
  isAvailable,
} from '@facilitronworks/react-native-windows-image-picker';

// Pick a single image
const result = await launchImageLibraryAsync({ base64: false });
if (!result.canceled) {
  const [asset] = result.assets!;
  console.log(asset.uri, asset.width, asset.height, asset.mimeType);
}

// Pick one or more arbitrary documents
const docs = await launchDocumentPickerAsync();
if (!docs.canceled) {
  for (const doc of docs.assets!) {
    console.log(doc.fileName, doc.fileSize, doc.mimeType);
  }
}

Result shape

{
  canceled: false,
  assets: [
    {
      uri: 'file:///.../LocalState/PickedFiles/<name>',
      fileName: 'photo.jpg',
      mimeType: 'image/jpeg',
      fileSize: 1048576,
      type: 'image',   // 'file' for documents
      width: 4032,     // images only
      height: 3024,
      base64: undefined,  // only when requested
      exif: null
    }
  ]
}

Cancelling resolves { canceled: true, assets: null } — it does not reject. Rejection is reserved for genuine failures.

Why files are copied

Every picked file is copied into LocalFolder\PickedFiles and the returned uri points at that copy. A StorageFile handed back by the picker carries broker-mediated access that does not reliably survive being passed to other subsystems as a plain path; copying gives you a stable location you can read, upload, and retry against. The module sweeps stale copies once per process on init, since nothing else ever deletes them.

API

FunctionDescription
launchImageLibraryAsync(options?)Pick a single image (image file types only).
launchDocumentPickerAsync(options?)Pick one or more files of any type.
requestMediaLibraryPermissionsAsync(writeOnly?)Always granted on desktop; for API symmetry.
getMediaLibraryPermissionsAsync(writeOnly?)As above.
isAvailable()true when running on Windows with the native module registered.

options.base64 is the only option honoured today. quality and selectionLimit are accepted and ignored by launchImageLibraryAsync (single-select).

Roadmap

  • Standalone .vcxproj + ReactPackageProvider + react-native.config.js so this installs and autolinks as a normal package
  • Verify the project actually compiles, and autolinks cleanly into a real app
  • ReactCoreInjection::GetTopLevelWindowId to make the WinMain hook optional
  • Example app + CI build
  • Camera capture (currently a separate module)
  • Folder picking / save picker
  • Publish to npm and register in react-native-community/directory

Contributing

Issues and PRs welcome — particularly build-wiring and RNW version-compat reports. This is maintained as a byproduct of a production app, so the honest maintenance promise is: it will keep working on the RNW versions that app ships on.

License

MIT — see LICENSE.

版本与发布记录

@facilitronworks/react-native-windows-image-picker 共发布 1 个版本,首次发布于 2026/07/18;过去 12 个月发布了 1 个版本。

版本发布日期距今
0.1.0-pre.0latest2026/07/183 个月前

关于 @facilitronworks/react-native-windows-image-picker 的常见问题

@facilitronworks/react-native-windows-image-picker 是什么?

A native image and document picker TurboModule for React Native Windows (new architecture), backed by Windows.Storage.Pickers.FileOpenPicker.

如何安装 @facilitronworks/react-native-windows-image-picker?

在项目目录运行 npm install @facilitronworks/react-native-windows-image-picker,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react-native(>=0.76.0)、react-native-windows(>=0.76.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@facilitronworks/react-native-windows-image-picker 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@facilitronworks/react-native-windows-image-picker 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@facilitronworks/react-native-windows-image-picker 可以商用吗?

@facilitronworks/react-native-windows-image-picker 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@facilitronworks/react-native-windows-image-picker 的下载量有多少?

根据 npm 官方下载统计,@facilitronworks/react-native-windows-image-picker 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,245 次,日均约 142 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@facilitronworks/react-native-windows-image-picker 还在维护吗?

最新版本 0.1.0-pre.0 发布于 2026/07/18(3 个月前);至今共发布 1 个版本,其中过去 12 个月发布了 1 个;首次发布于 2026/07/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。