It's 2026 and My Uni-app App Is Rejected for a Privacy Popup Not Shown First — I Did Show It, So Are the SDKs Running First?
When a Uni-app-built App is rejected by an app store with the message 'privacy policy was not shown before launch,' in most cases the problem is not that you forgot the popup. The problem is the order in which it appears: it runs after third-party SDKs for analytics, push, maps, and so on are initialized, or after the home page request. Reviewers look at three states — first launch, overwrite install, and no consent record — and ask whether any information was read before consent, not whether you have a popup component. In 2026, privacy compliance standards across app stores are getting stricter, and order issues cause rejections more often than popup design.
Why the Order — Not the Popup Itself — Is Usually What Gets Rejected
The App-side startup chain in Uni-app is roughly main.js → App.vue's onLaunch → the first page's onLoad and onReady. To 'make the home page faster,' many projects stuff SDK initialization, remote config fetching, and hot update checks into onLaunch, while the popup waits until the page is rendered. In the code these two things look unrelated, but from the review side they are not: before the popup ever appears, device information, the clipboard, or the installed app list may already have been read.
A privacy popup is not essentially a screen; it is a gate: it keeps every behavior that reads user information behind consent. To tell whether your project has a gate or just decoration, one action is enough — install and open it for the first time on a clean device, watch network requests and runtime logs, and see whether any request is sent before consent. The pass line is: no collection before consent, basic functions usable after refusal, and the privacy policy can be reopened. Miss one of the three and you are likely to fail review.
- First installation: easiest to pass, and easiest to leave untested
- Overwrite install, launch after clearing data: the upgrade path for existing users often goes unverified
- Cold start into a deep page: scanning a QR code, a push notification, or a share link goes straight to a second-level page, and the popup often fails to appear
- After refusal: users must still be able to browse; no blank screen, no crash, no immediate exit
A Nameable Troubleshooting Framework: One Checklist, Two Gates, Three Pieces of Evidence
Breaking this into 'checklist — timing — evidence' helps because the three parts are usually owned by different people: product confirms the checklist, front-end implements the timing, and operations uploads the evidence in the app store console. Discuss them all together and the usual result is 'we changed everything and it still got rejected,' followed by back-and-forth blame.
Checklist Layer: SDK and Permission Reconciliation
- List every third-party SDK and native plugin in the project, including analytics, push, maps, payment, customer service, and hot updates
- Annotate each one: what information it reads, when it initializes, and whether it can be delayed until after user consent
- Align them line by line with the permission list and SDK list declared in the app store console
Note: a mismatch between the checklist and actual behavior is a very common cause of rejection. It has little to do with whether the code is well written; it is a disconnect between documentation and implementation.
Timing Layer: Two Gates
- Front gate: intercept before the first business page renders, and attach SDK initialization to the callback after user consent rather than letting it run on its own with onLaunch
- Fallback gate: after refusal, use a degraded path — do not collect non-essential information, keep basic functions usable, and keep an entry point for consenting again
Note: mini-program authorization popups and H5 cookie prompts are not the same as this App flow. Isolate them with conditional compilation in APP-PLUS blocks. Do not force one set of logic to serve all three platforms, or you will change one platform and break the other two.
Evidence Layer: Three Submittable Materials
- Popup copy and the full privacy policy, with each item matching what is actually collected
- Screenshots or screen recordings of the path for refusing and withdrawing consent
- Permission and SDK declaration records in each app store console
These three usually cannot be finalized by the front-end developer alone. Check them before delivery, or you will easily end up with the code changed while the copy is still waiting for approval.
On the Delivery Floor: How Much Time Does One Rejection Usually Cost?
In real projects the common situation is this: review queuing itself typically takes 1-3 business days; after a rejection you have to change copy or adjust the order, then redo cloud packaging, resubmit, and queue again. Constraints often include a campaign date already being fixed, copy waiting for product and legal confirmation, and assets still missing a few pages. The practice is to run three passes on a clean device before submission — first install, overwrite install, and launch after clearing data — and capture logs before and after consent each time. In enterprise project delivery habits, this kind of self-check usually goes into the pre-submission checklist. The cost is straightforward: skip this self-check and one round trip often takes about a week, so if it hits a promotion date, launch can only be postponed; worse is a random audit after launch, which may require rectification and can even lead to removal. The experience range here is: from rejection notice to passing review again, 2-4 business days when things go smoothly; when copy and legal confirmation or extra app store review is involved, the typical range stretches to 5-10 business days.
A Few Recurring Pitfalls
- Using a delayed popup instead of order control: by the time setTimeout fires, the SDK has already run
- Showing the popup only in the home page's onLoad: it fails to appear when a cold start goes straight to a second-level page
- Using uni.showModal as the privacy popup: button copy and styles are uncontrollable, and some app stores do not accept it
- Pointing the privacy policy to a webview, but the URL does not open or goes to an internal network
- Updating the privacy policy content without a second confirmation in the App
- Testing only the App side and forgetting that the H5 and mini-program sides of the same codebase each have their own rules
Custom Popup Component vs. Third-Party Compliance Plugin: How to Choose
- Custom component: highly controllable and can match branding and interaction, but the downside is that you have to track rule changes in each app store yourself. The integration experience range is about 0.5-2 person-days, excluding copy and legal confirmation time. Suitable for projects with a long-term in-house maintenance team.
- Third-party compliance plugin: fast to integrate, and rule updates follow the plugin; the cost is extra SDKs and package size, plus you need to check whether these SDKs' collection declarations add to your declaration burden. The integration experience range is about 1-3 person-days. Suitable for one-off delivery projects where the client has no dedicated compliance staff.
- The cost of choosing wrong: you build your own but no one maintains the rules, so months later you may be rejected again due to new app store rules; or you use a plugin but do not check the declarations, so what is filled in the app store console does not match what is actually collected.
Applicable Scenarios and Boundaries
Typical cases where this layer deserves serious work: you need to publish to common domestic app stores, you have integrated push or analytics third-party SDKs, you have account login or payment features, or an external team delivered the project and the client operates it afterward. Conversely, unreleased test packages, internal enterprise distribution, and pure H5 or pure mini-program projects usually do not need to copy this App process; just follow each platform's own rules. One more point to be clear about: the privacy popup is a publishing threshold, not an experience optimization. It solves whether you can pass review; it does not solve retention or conversion, so do not expect it to improve your metrics along the way.
Frequently Asked Questions
Must the Uni-app privacy popup appear before the launch page?
The common practice is to show it before the first business page renders and before any third-party SDK initialization, ahead of the home page data request; the exact timing should follow each app store's current review rules.
If I use conditional compilation to separate App and mini-program, will maintenance cost double?
Only isolate the parts that differ — put the popup and SDK initialization in the APP-PLUS block, keep shared logic reused as usual, and the maintenance load is usually within an acceptable range.
If the user taps refuse, can they still keep using the App?
Under common review standards, basic functions should remain usable after the user refuses non-essential collection; only prompt when a core function truly depends on it, provide an entry point to consent again, and do not exit the App directly.
Is there any difference between cloud packaging and local packaging for privacy?
There is no essential difference in implementation, but cloud packaging includes the platform's preset native modules, so popup order is easier to overlook. Before submission, verify both methods once each.
Next step: add these four items to the pre-submission checklist — first install on a clean device, no collection before consent, usable after refusal, and the policy can be reopened — and have product, front-end, and operations each confirm them once. This process suits Apps that need to be published to domestic app stores; pure internal test packages, pure H5, or mini-program projects do not need to copy it. Rules are subject to each app store's current review standards.
-
An H5 campaign page embedded in Flutter scrolls rough on Android—which layer should you touch first?
Date: Oct 14, 2026 Read: 6
-
It's 2026 and the page title isn't in the source code — where does Baidu get the indexed title?
Date: Oct 13, 2026 Read: 10
-
OnPush child component not refreshing with polling data in Angular: replace the array reference first, or add markForCheck first?
Date: Oct 12, 2026 Read: 15
-
It's 2026, two dialogs in Vue share the same composable—one fails to submit and the other also shows an error. Is state leaking?
Date: Oct 11, 2026 Read: 32
-
It's 2026 — why does await inside forEach send all requests before waiting for results?
Date: Oct 9, 2026 Read: 24




