Skip to content

Latest commit

 

History

History
453 lines (354 loc) · 23.9 KB

File metadata and controls

453 lines (354 loc) · 23.9 KB

react-native-set-live-wallpaper

License: MIT

Set static images and video wallpapers from an Expo or React Native app. Android opens the native wallpaper workflow; iOS exports media to Photos so the user completes the wallpaper action in Apple's supported UI.

Requires a development or production build. Expo Go cannot load this custom native module.

Features

  • Static wallpapers from local images and remote HTTP(S) URLs.
  • Android native Home screen, Lock screen, and Both destination flow.
  • Android live MP4 wallpaper with drag, pinch, and zoom positioning.
  • Themeable Android library previews.
  • An iOS Photos album named after the host app.
  • iOS MP4-to-Live-Photo conversion for Lock Screen motion on iOS 17+.
  • Cleanup for temporary files and library-owned iOS Photos assets.
  • Expo config plugin for Android wallpaper declarations and iOS Photos permissions.

Installation

Install with pnpm:

pnpm add react-native-set-live-wallpaper

This package uses Expo Modules. Rebuild your native app after installing:

npx expo prebuild
pnpm ios
# or
pnpm android

For a dynamic Expo config, add the config plugin explicitly:

// app.config.ts
export default {
  expo: {
    plugins: ['react-native-set-live-wallpaper'],
  },
};

The plugin adds Android's wallpaper service and SET_WALLPAPER permission, plus the iOS Photos usage descriptions. Rebuild after adding or upgrading the package.

Quick start

import { setLiveWallpaperFromUrl, setWallpaperFromFile } from 'react-native-set-live-wallpaper';

const staticResult = await setWallpaperFromFile({
  source: 'file:///path/to/photo.jpg',
  target: 'both',
});

const liveResult = await setLiveWallpaperFromUrl({
  source: 'https://example.com/wallpaper.mp4',
  muted: true,
  loop: true,
  iosLivePhotoDuration: 2,
});

These methods open a native user flow and normally return requires-user-action. This means the system or Photos workflow is ready; it does not mean the wallpaper has already been applied.

How it works

Platform Static image Video / live wallpaper
Android Stages the image privately, then opens Android's native crop-and-set screen by default. The device controls the final Home / Lock / Both choices. Stores one private active MP4 for the live-wallpaper service, opens a positioning preview by default, then opens Android's live-wallpaper confirmation UI.
iOS Saves the image in a Photos album named after the host app. The user opens it in Photos and chooses Share → Use as Wallpaper. Opens a native drag-and-zoom preview, bakes that crop into a paired Live Photo, and saves it in the app album for manual Lock Screen setup on iOS 17+.
Web Not supported. Not supported.

Apple provides no public API for an app to apply a wallpaper directly. iOS always needs the user to finish in Photos or Settings.

Android behavior

  • previewMode: 'system' is the default for static images. It prefers the device's current wallpaper preview and uses Android's legacy cropper only as a compatibility fallback.
  • previewMode: 'library' uses this package's themeable preview and reliable Home / Lock / Both picker.
  • One private MP4 remains while it is the active live wallpaper because the Android wallpaper service must play it after the app closes. It is replaced when another video is chosen and is never added to Gallery.
  • Temporary static-image and download-staging files are removed after the flow finishes.

iOS behavior

  • The module creates or reuses a regular Photos album named from CFBundleDisplayName, the host app's display name.
  • It requests Photos read/write access to organize the album and support cleanup.
  • Every live-video call opens a full-screen native preview. Drag to position the video, pinch to zoom, then tap Continue. The exported video and Live Photo poster use the selected crop.
  • Remote iOS videos stream into the preview immediately while the complete conversion file downloads in the background. A loading indicator is shown until playback is ready.
  • Local iOS videos support regular file:// paths plus Photos-library ph:// and assets-library:// identifiers.
  • Live Photo conversion uses the complete video by default. Set iosLivePhotoDuration to a positive number to convert only that many seconds from the beginning.
  • Apple does not publish a custom Live Photo wallpaper duration limit. For the most reliable Lock Screen motion, use a short one-to-two-second value; longer exports may remain playable in Photos but be rejected for animated wallpaper.
  • Call deleteSavedWallpaperAsset() only after the user has finished setting the wallpaper.
  • The iOS Simulator can show a black wallpaper canvas for imported Photos. Test the final wallpaper flow on a physical iPhone.

API

Import the functions you need from the package:

import {
  WallpaperError,
  clearCachedFiles,
  deleteSavedWallpaperAsset,
  getPlatformCapabilities,
  isSupported,
  setLiveWallpaperFromFile,
  setLiveWallpaperFromUrl,
  setWallpaperFromFile,
  setWallpaperFromUrl,
} from 'react-native-set-live-wallpaper';

setWallpaperFromFile(options)

Prepares a local static image.

const result = await setWallpaperFromFile({
  source: localImageUri,
  target: 'both',
  previewMode: 'system',
});

Use a file:// URI on iOS. Android accepts file:// and content:// URIs.

setWallpaperFromUrl(options)

Downloads and prepares a static image from an HTTP(S) URL.

const result = await setWallpaperFromUrl({
  source: 'https://cdn.example.com/wallpaper.jpg',
  target: 'home',
});

setLiveWallpaperFromFile(options)

Prepares a local MP4 file as a live wallpaper.

const result = await setLiveWallpaperFromFile({
  source: localVideoUri,
  muted: true,
  iosLivePhotoDuration: 2,
  showSystemPreview: true,
});

setLiveWallpaperFromUrl(options)

Downloads an MP4 and prepares it as a live wallpaper.

const result = await setLiveWallpaperFromUrl({
  source: 'https://cdn.example.com/wallpaper.mp4',
  muted: true,
  loop: true,
  iosLivePhotoDuration: 2,
  posterImage: 'https://cdn.example.com/poster.jpg',
});

getPlatformCapabilities()

Returns the feature support reported by the installed native platform.

const capabilities = await getPlatformCapabilities();
// {
//   platform: 'android' | 'ios',
//   staticWallpaper: boolean,
//   lockScreen: boolean,
//   liveVideo: boolean,
//   remoteSource: boolean,
//   crop: boolean,
//   requiresUserAction: true,
//   implementationPhase: number,
// }

Use this before showing live-wallpaper UI. On iOS, liveVideo is true only on iOS 17 or later.

isSupported(feature)

Checks one named feature:

const supportsVideo = await isSupported('live-video');

Accepted feature names: 'static-home', 'static-lock', 'live-video', 'remote-source', and 'crop'.

clearCachedFiles()

Deletes temporary download and conversion files created by the module.

await clearCachedFiles();

On Android, this does not remove the active private MP4 currently used by the live-wallpaper service.

deleteSavedWallpaperAsset(assetId)

Deletes an iOS Photos asset that this library previously created.

const result = await setWallpaperFromFile({ source: localImageUri });

if (result.platform === 'ios' && result.status === 'requires-user-action' && result.assetId) {
  // Wait until the user has finished setting the wallpaper in Photos.
  await deleteSavedWallpaperAsset(result.assetId);
}

It resolves to true when the library-owned asset was deleted and false when the identifier is unknown or no longer exists. It is a no-op on Android and web.

Options

Static wallpaper options

Option Type Default Description
source string required Local URI for setWallpaperFromFile, or HTTP(S) URL for setWallpaperFromUrl.
target 'home' / 'lock' / 'both' 'both' Destination for Android's library preview. The Android system preview owns its own selector; iOS ignores it.
crop CropConfiguration Validated crop data for callers that persist their own position. Current native previews position interactively; iOS uses Apple's editor.
allowBackup boolean true Android library-preview only. Passes Android's wallpaper backup preference to WallpaperManager.
previewMode 'system' / 'library' 'system' Android only. system uses the OS screen; library uses this package's themeable image preview.
showTargetPicker boolean true Android library-preview only. Shows Home / Lock / Both after positioning.
previewStyle WallpaperPreviewStyle Android library-preview only. Colors and labels for the package preview.

Live wallpaper options

Option Type Default Description
source string required Local MP4 URI (file://, iOS ph://, or assets-library://) for setLiveWallpaperFromFile, or HTTP(S) MP4 URL for setLiveWallpaperFromUrl.
crop CropConfiguration Initial normalized position and zoom for the native preview. The user's final interactive crop is baked into the Android wallpaper or iOS Live Photo.
muted boolean true Mutes Android playback and removes audio when iOS converts the MP4 to a Live Photo.
loop boolean true Android only. Controls whether the live wallpaper repeats. iOS controls Live Photo playback.
iosLivePhotoDuration number full video iOS only. Converts this many seconds from the beginning. Values longer than the source are capped to the source duration.
showSystemPreview boolean true Android only. true opens the package positioning preview before Android confirmation; false opens Android's general live-wallpaper chooser.
previewStyle WallpaperPreviewStyle Colors and labels for the Android and iOS native video positioning previews.
posterImage string iOS only. Local file or HTTP(S) image used as the Live Photo key image. When omitted, a frame from the video is used.

CropConfiguration

type CropConfiguration = {
  mode: 'cover' | 'contain' | 'stretch';
  position?: { x: number; y: number };
  scale?: number;
};

position.x and position.y must be between 0 and 1; scale must be greater than 0.

WallpaperPreviewStyle

Used by Android's package-provided previews and the iOS live-video crop preview. Static iOS exports do not use it.

The preview is a native full-screen controller, so it cannot render React components or accept a React Native StyleSheet object. The nested options below control each native section. Numeric sizes use points on iOS and density-independent pixels on Android. Colors accept #RRGGBB or #AARRGGBB.

Option Type Description
backgroundColor string Color behind the image or video.
statusBar 'hidden' / 'light' / 'dark' Hides the status bar or selects light/dark status-bar content. Defaults to light.
instruction WallpaperPreviewInstructionStyle Drag/pinch instruction chip.
controls WallpaperPreviewControlsStyle Container holding Cancel and Continue.
cancelButton WallpaperPreviewButtonStyle Cancel button appearance and label.
continueButton WallpaperPreviewButtonStyle Continue button appearance and label.
loading WallpaperPreviewLoadingStyle Video loading indicator, message, and error message.

Shared instruction, button, and loading appearance options:

Option Type Description
visible boolean Shows or hides the element.
backgroundColor string Element background color.
textColor string Label color.
fontSize number Label size.
fontWeight 'regular' / 'medium' / 'semibold' / 'bold' Label weight.
fontFamily string Installed native font/PostScript family name.
textAlign 'left' / 'center' / 'right' Label alignment.
cornerRadius number Rounded-corner radius.
borderColor string Border color.
borderWidth number Border width.
paddingHorizontal number Left and right content padding.
paddingVertical number Top and bottom content padding.

instruction also supports text, position: 'top' | 'center' | 'bottom', marginHorizontal, marginVertical, and optional height. cancelButton and continueButton support text and height.

controls options:

Option Type Description
backgroundColor string Controls-container color.
position 'top' / 'bottom' Places the controls container at the top or bottom.
direction 'horizontal' / 'vertical' Arranges the two buttons in a row or column.
blurEffect 'none' / 'light' / 'dark' / 'system' iOS background blur. Android uses backgroundColor.
cornerRadius number Container corner radius.
borderColor string Container border color.
borderWidth number Container border width.
paddingHorizontal number Internal horizontal padding.
paddingVertical number Internal vertical padding.
marginHorizontal number Space between the container and screen sides.
marginVertical number Space between the container and its selected screen edge.
gap number Space between Cancel and Continue.

loading also supports text, errorText, indicatorColor, marginHorizontal, and marginVertical.

import type { WallpaperPreviewStyle } from 'react-native-set-live-wallpaper';

const previewStyle = {
  backgroundColor: '#050706',
  statusBar: 'hidden',
  instruction: {
    text: 'Drag to position · Pinch to zoom',
    position: 'top',
    backgroundColor: '#B319211C',
    textColor: '#FFFFFF',
    fontSize: 15,
    fontWeight: 'semibold',
    cornerRadius: 18,
    paddingHorizontal: 16,
    paddingVertical: 9,
    marginHorizontal: 24,
    marginVertical: 16,
  },
  controls: {
    position: 'bottom',
    direction: 'horizontal',
    backgroundColor: '#CC050706',
    blurEffect: 'system',
    cornerRadius: 24,
    paddingHorizontal: 12,
    paddingVertical: 12,
    marginHorizontal: 16,
    marginVertical: 16,
    gap: 12,
  },
  cancelButton: {
    text: 'Cancel',
    backgroundColor: '#1FFFFFFF',
    textColor: '#FFFFFF',
    cornerRadius: 16,
    fontWeight: 'bold',
    height: 52,
  },
  continueButton: {
    text: 'Choose screen',
    backgroundColor: '#D9FF69',
    textColor: '#172000',
    cornerRadius: 16,
    fontWeight: 'bold',
    height: 52,
  },
  loading: {
    text: 'Preparing preview…',
    errorText: 'This video could not be loaded',
    textColor: '#FFFFFF',
    indicatorColor: '#D9FF69',
  },
} satisfies WallpaperPreviewStyle;

The earlier flat keys (controlsBackgroundColor, instructionBackgroundColor, accentColor, accentTextColor, textColor, instructionText, cancelText, and continueText) remain supported for backward compatibility, but the nested API is recommended.

Results and errors

WallpaperResult

Result Meaning
{ status: 'set', platform: 'android' } Reserved direct-set result type. Current Android flows normally return requires-user-action because they open system confirmation UI.
{ status: 'requires-user-action', platform, instructions?, assetId? } The native wallpaper flow or iOS Photos export is ready. assetId is returned for iOS-created Photos assets.
{ status: 'cancelled', platform } The user cancelled a package-controlled flow.

Failures reject with WallpaperError, which contains a code and message:

try {
  await setWallpaperFromUrl({ source: imageUrl });
} catch (error) {
  if (error instanceof WallpaperError) {
    console.log(error.code, error.message);
  }
}
Error code Typical cause
E_INVALID_SOURCE Empty URI or the wrong URI scheme for the selected function.
E_INVALID_CROP Invalid crop position or scale.
E_NETWORK A remote source could not be downloaded.
E_DECODING The image or video could not be read or converted.
E_PERMISSION_DENIED Photos access was denied on iOS.
E_UNSUPPORTED_FEATURE The platform, OS version, or required system handler does not support the requested action.

Source URI rules

Function family Allowed source
*FromUrl http:// or https://
*FromFile on Android file:// or content://
*FromFile on iOS file://

For Expo ImagePicker, use its returned asset.uri:

import * as ImagePicker from 'expo-image-picker';
import { setWallpaperFromFile } from 'react-native-set-live-wallpaper';

const picked = await ImagePicker.launchImageLibraryAsync({
  mediaTypes: ['images'],
  quality: 1,
});

if (!picked.canceled) {
  await setWallpaperFromFile({ source: picked.assets[0].uri });
}

Example app

This repository includes a complete Expo example with local and remote static-image and MP4 actions:

pnpm install
pnpm build
pnpm --dir example ios
# or
pnpm --dir example android

The bundled image is “Mountains Landscape” on Wikimedia Commons, released under CC0. The remote example video is Mixkit's “Waterfall Between Green Hills” under the Mixkit Stock Video Free License.

Requirements

  • Expo SDK 57 or a compatible React Native app with Expo Modules.
  • A development or production build.
  • Android device with a wallpaper provider.
  • iOS 16.4+ for static image export; iOS 17+ for MP4-to-Live-Photo conversion.

License

MIT © 2026 Aziz Falah Hassan (Aziz-AXG)