Skip to content

IShix-g/NativePrompt

Repository files navigation

Unity

Native Prompt

Native Prompt is a native UI plugin for Unity. It provides alerts, bottom sheets, toasts, loading overlays, and in-app review requests on iOS and Android through one small C# API.

Native Prompt Top

Table of Contents

Requirements

  • Unity 6000.0 or later
  • iOS 13 or later
  • Android API level 24 or later

The Android prompt UI uses Android SDK dialogs and views. It does not require Material Components, Compose, or another external UI library. Store Review uses Google Play In-App Review com.google.android.play:review:2.0.2, resolved by the package's Android Library.

Installation

The package ID is com.ishix.nativeprompt.

To install it with Unity Package Manager:

  1. Open Window > Package Manager in Unity.
  2. Select Install package from git URL from the add menu.
  3. Enter the following URL:
https://github.com/IShix-g/NativePrompt.git?path=/Packages/com.ishix.nativeprompt#v1

You can instead add the package directly to your project's Packages/manifest.json:

{
  "dependencies": {
    "com.ishix.nativeprompt": "https://github.com/IShix-g/NativePrompt.git?path=/Packages/com.ishix.nativeprompt#v1"
  }
}

Quick Start

Start with the included sample to try every API without writing setup code.

  1. Open Window > Package Manager.
  2. Select Native Prompt, then open the Samples tab.
  3. Import Native Prompt Sample.

Import Native Prompt Sample from Package Manager

  1. Open Assets/Samples/Native Prompt/{version}/Native Prompt Sample/NativePromptSample.unity.
  2. Enter Play Mode and use the sample controls.

Native Prompt sample controls

For common application flows, see Recipes.

Unity Editor Preview

Alert, Bottom Sheet, Toast, Loading, and Store Review have interactive, iOS-inspired previews in the Game view while running in the Unity Editor. Store Review uses an image-free simulation and writes a test log; it does not report whether the platform would display or accept a review. Preview assets are Editor-only and loaded through AssetDatabase, so they are not included in player builds.

Native Alert

Use an alert for a confirmation or a short notice. Content is required. When Yes and No are omitted, Native Prompt displays one close button.

NP.ShowAlert(
    new AlertOptions
    {
        Title = "Delete save?",
        Content = "This cannot be undone.",
        YesButtonText = "Delete",
        NoButtonText = "Keep"
    },
    result =>
    {
        if (result == AlertResult.Yes)
        {
            DeleteSave();
        }
    })
    .AddTo(this);
Optional: view the Awaitable version
private async Awaitable DeleteSaveWithConfirmationAsync(
    CancellationToken cancellationToken = default)
{
    // Link cancellation to this GameObject's lifecycle.
    using var linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
        cancellationToken,
        destroyCancellationToken);

    AlertResult result = await NP.ShowAlertAsync(
        new AlertOptions
        {
            Title = "Delete save?",
            Content = "This cannot be undone.",
            YesButtonText = "Delete",
            NoButtonText = "Keep"
        },
        linkedCancellation.Token);

    if (result == AlertResult.Yes)
    {
        DeleteSave();
    }
}

Alerts are shown one at a time in request order. On Android, the Back button and a backdrop tap do not close an alert.

See the Alert API reference for all options, results, queue behavior, and manual dismissal.

Native Bottom Sheet

Use a bottom sheet to offer one to three actions. Give each action a stable, unique ID and handle that ID in the callback.

NP.ShowBottomSheet(
    new BottomSheetOptions
    {
        Title = "Photo",
        Actions = new[]
        {
            new BottomSheetAction
            {
                Id = "share",
                Text = "Share"
            },
            new BottomSheetAction
            {
                Id = "delete",
                Text = "Delete",
                Style = BottomSheetActionStyle.Destructive
            }
        }
    },
    result =>
    {
        if (!result.IsCancelled)
        {
            RunPhotoAction(result.ActionId);
        }
    })
    .AddTo(this);
Optional: view the Awaitable version
private async Awaitable ShowPhotoActionsAsync(
    CancellationToken cancellationToken = default)
{
    // Link cancellation to this GameObject's lifecycle.
    using var linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
        cancellationToken,
        destroyCancellationToken);

    BottomSheetResult result = await NP.ShowBottomSheetAsync(
        new BottomSheetOptions
        {
            Title = "Photo",
            Actions = new[]
            {
                new BottomSheetAction
                {
                    Id = "share",
                    Text = "Share"
                },
                new BottomSheetAction
                {
                    Id = "delete",
                    Text = "Delete",
                    Style = BottomSheetActionStyle.Destructive
                }
            }
        },
        linkedCancellation.Token);

    if (!result.IsCancelled)
    {
        RunPhotoAction(result.ActionId);
    }
}

A cancel button, backdrop tap, or Android Back returns a cancelled result. Disabled actions can remain visible without being selectable.

See the Bottom Sheet API reference for action options, result values, validation, and dismissal behavior.

Native Toast

Use a toast for brief feedback that does not interrupt the current flow.

NP.ShowToast(
    new ToastOptions
    {
        Message = "Saved",
        Position = ToastPosition.Bottom
    },
    reason => Debug.Log($"Toast dismissed: {reason}"))
    .AddTo(this);
Optional: view the Awaitable version
private async Awaitable ShowSavedToastAsync(
    CancellationToken cancellationToken = default)
{
    // Link cancellation to this GameObject's lifecycle.
    using var linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
        cancellationToken,
        destroyCancellationToken);

    ToastDismissReason reason = await NP.ShowToastAsync(
        new ToastOptions
        {
            Message = "Saved",
            Position = ToastPosition.Bottom
        },
        linkedCancellation.Token);

    Debug.Log($"Toast dismissed: {reason}");
}

Toasts dismiss automatically after 2.5 seconds by default. Only one toast is visible at a time; a new toast replaces the previous one. Keep the returned handle when you disable automatic dismissal and need to close the toast yourself.

See the Toast API reference for duration, tap behavior, positions, and dismissal reasons.

Native Loading

Use Loading while an operation such as a purchase or network request is running. Loading does not end automatically, so keep the returned handle and dismiss it on every success, failure, and cancellation path.

private LoadingHandle _loading;

public void BeginPurchase()
{
    _loading?.Dismiss();
    _loading = NP.ShowLoading(new LoadingOptions
    {
        BlocksInteraction = true,
        ShowsBackground = true,
        Position = LoadingPosition.Center,
        Message = "Processing..."
    }).AddTo(this);
}

public void EndPurchase()
{
    _loading?.Dismiss();
    _loading = null;
}

Input blocking and background visibility are separate options. Visual elements appear after a short delay by default, which avoids flashing the spinner for quick operations. Multiple loading handles may coexist; the newest active request controls the shared loading view.

At corner positions, the message sits toward the inside of the screen and the spinner stays on the outside edge. At Center, the message appears below the spinner. Long messages are limited to two lines at corners and four lines at the center.

See the Loading API reference for appearance options, delayed display, overlapping requests, and lifecycle events.

Native Store Review

Request the platform-native rating and review flow:

NP.RequestReview();

Native Prompt only sends the request. The platform may choose not to display the dialog, and no display or submission result is returned. No additional project configuration is required.

Call it after a meaningful user interaction. See the Store Review API reference for timing, platform behavior, localization, and device testing.

ShowAlert(), ShowBottomSheet(), ShowToast(), and ShowLoading() each return a handle for that request. The optional Show*Async() variants for Alert, Bottom Sheet, and Toast return a Unity Awaitable<T> instead; control their lifetime with a CancellationToken.

  • Call Dismiss() to close it and deliver the normal dismissal result.
  • Call Dispose() to remove Alert, Bottom Sheet, or Toast without a result callback or completion event.
  • Chain AddTo(this) to clean up automatically when the owning MonoBehaviour is destroyed.
  • Use RequestId, Tag, and GroupId to identify a request. Tags and groups are metadata; they do not dismiss related prompts automatically.

Both Dismiss() and Dispose() are safe to call more than once. Loading has no per-request result callback; LoadingEnded reports how its request ended.

AlertHandle alert = NP.ShowAlert(new AlertOptions
{
    Content = "Continue?"
}).AddTo(this);

// Close this specific alert later if needed.
alert.Dismiss();

See the Handle lifetime reference for ownership, disposal, metadata, and AddTo behavior.

Use the callback passed to Show*() when only the caller needs the result. Use static lifecycle events when another part of the application needs to observe all prompts of a type.

UI Displayed Finished
Alert NP.AlertOpened NP.AlertCompleted
Bottom Sheet NP.BottomSheetOpened NP.BottomSheetCompleted
Toast NP.ToastShown NP.ToastDismissed
Loading NP.LoadingStarted NP.LoadingEnded

For application-wide behavior that should change while any Loading request is active, use NP.LoadingStateChanged and initialize from NP.IsLoading:

private void OnEnable()
{
    NP.LoadingStateChanged += OnLoadingStateChanged;
    OnLoadingStateChanged(NP.IsLoading);
}

private void OnDisable()
{
    NP.LoadingStateChanged -= OnLoadingStateChanged;
}

private void OnLoadingStateChanged(bool isLoading)
{
    Debug.Log(isLoading ? "Loading started" : "Loading ended");
}

Replace the log with application behavior such as muting audio or pausing selected events. The event runs only when the first Loading starts or the last one ends.

Subscribe and unsubscribe with the listener's lifecycle because NP events are static:

private void OnEnable()
{
    NP.AlertCompleted += OnAlertCompleted;
}

private void OnDisable()
{
    NP.AlertCompleted -= OnAlertCompleted;
}

private void OnAlertCompleted(AlertCompletedEventArgs args)
{
    Debug.Log($"{args.RequestId}: {args.Result}");
}

Callbacks and events run on the Unity main thread. For a completion, the per-request callback runs before the static event. LoadingStarted reports that a request was accepted, which may be before its delayed spinner becomes visible.

See the Lifecycle event reference for event arguments, metadata, delivery order, Loading counts, and end reasons.

Sample Scene

The imported sample includes Alert, Bottom Sheet, Toast, Loading, and Store Review test controls and displays their latest results. Loading controls cover spinner sizes, representative positions, a message, background/input blocking, and manual dismissal. The Store Review result reports only that the request was called. Follow Quick Start to import and open it.

Documentation

License

This project is licensed under the MIT License. See LICENSE.

About

A Unity plugin for displaying platform-native alerts, bottom sheets, loading indicators, toasts, and store review prompts on iOS and Android.

Topics

Resources

Stars

Watchers

Forks

Releases

Sponsor this project

Contributors

Languages