首页 > 经验记录 > RenPy因video_play_edit_sdk导致应用商店审核不通过的问题修复,套壳隐私政策绕过检测

RenPy因video_play_edit_sdk导致应用商店审核不通过的问题修复,套壳隐私政策绕过检测

环境:RenPy 8.5

工作目录:renpy-8.5.0-sdk\rapt\project (就是安装完RenPy安卓环境后,对应的构建目录)

 

RenPy 打包安卓很简单,配置好Java环境,在 RenPy Launcher 里 Grade 下依赖的时候让自己的主机能够访问境外网络,剩下的就是点点点。

但是打包完安卓,要上线国内的应用商店,那就有点麻烦。

因为我发现,构建出来的apk启动的一瞬间就已经加载了对应的 video_play_edit_sdk 这个SDK,这个东西放在国内属于未经用户同意收集手机传感器,正经应用商店肯定是会给你打回的,必须要先同意收集,然后你才能真的收集,不能用户什么都没做一打开apk就在后台收集。

TapTap审核打回例:APP未见向用户明示个人信息收集使用的目的、方式和范围,未经用户同意,存在收集传感器的行为。

 

我尝试了一些方法,发现没有任何在RenPy配置内部绕过的机制,这就很尴尬。

所以我们只能在外面绕,意思就是说 在安卓层绕

我们把RenPy的构建逻辑给他改一改,相当于hack一下原本的启动方式。

RenPy安卓端的默认机制是直接拉起 PythonSDLActivity 这个安卓Activity,不要用他这个,因为一启动,sdk就加载了。

 

 

我们就自己重新写个新的 Activity,启动的时候先启动我们的,然后这个Activity的作用就是相当于套个壳子,先给用户操作了先,让他同意隐私政策、同意我们收集传感器(你真的在收集,所以隐私政策里必须写上)

用户不同意,就直接退出,整个逻辑和RenPy原生构建出的东西没有任何关系。

等用户点击同意按钮了,我们就自己把原生的 PythonSDLActivity  给拉起来,哎这样就完美了。

 

做法也很简单,我这里有两个现成的类,直接复制进去即可。

1、renpy-8.5.0-sdk\rapt\project\app 子模块,src/main/AndroidManifest.xml 替换,目的是启动自己写的安卓壳子,而非启动原始的 PythonSDLActivity

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">

    <application
            android:allowBackup="true"
            android:fullBackupContent="@xml/backup"
            android:fullBackupOnly="true"
            android:icon="@mipmap/icon"
            android:label="@string/appName"
            android:isGame="true"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:hardwareAccelerated="true">

        <activity
                android:name="org.renpy.android.PrivacyActivity"
                android:exported="true"
                android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar"
                android:screenOrientation="landscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <activity
                android:name="org.renpy.android.PythonSDLActivity"
                android:label="@string/iconName"
                android:alwaysRetainTaskState="true"
                android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
                android:launchMode="singleTop"
                android:screenOrientation="sensorLandscape"
                android:exported="true"
        >
        </activity>

        <provider
                android:name="org.renpy.android.RenPyFileProvider"
                android:authorities="cn.noctella.galgod.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths"/>
        </provider>

        

    </application>

    <uses-feature android:glEsVersion="0x00030000" android:required="true"/>

    <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>

    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET" />

    

    
    
    <uses-permission android:name="android.permission.VIBRATE"/>
    
    
    
    <uses-permission android:name="android.permission.INTERNET"/>
    
    

    
</manifest>

 

2、腾笼换鸟,塞自己的具体壳子,直接新建/复制进去到对应位置

renpy-8.5.0-sdk\rapt\project\renpyandroid 子模块,新建  src/main/java/org/renpy/android/PrivacyActivity.java

package org.renpy.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.FrameLayout;

public class PrivacyActivity extends Activity {

    private static final String PREFS_NAME = "PrivacyPrefs";
    private static final String KEY_ACCEPTED = "hasAcceptedPrivacy";
    private static final String PRIVACY_URL = "https://www.baidu.com";

    private Button positiveButton;
    private int countdown = 5;
    private final Handler handler = new Handler(Looper.getMainLooper());
    private AlertDialog privacyDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 1. 立即检查权限,已同意直接跳过
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        if (prefs.getBoolean(KEY_ACCEPTED, false)) {
            startRenPyGame();
            return;
        }

        // 2. 建立一个纯黑色的根布局,彻底杜绝系统默认的白屏
        FrameLayout root = new FrameLayout(this);
        root.setBackgroundColor(Color.BLACK);
        setContentView(root);

        // 3. 稍作延迟弹出对话框,确保窗口句柄准备就绪
        handler.postDelayed(this::showPrivacyDialog, 200);
    }

    private void showPrivacyDialog() {
        if (isFinishing() || isDestroyed()) return;

        WebView webView = new WebView(this);
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        // 禁用硬件加速防止部分老机型 WebView 渲染失败(可选,但稳健)
        webView.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);

        webView.setWebViewClient(new WebViewClient());

        // 容器设置
        FrameLayout provider = new FrameLayout(this);
        int padding = (int) (20 * getResources().getDisplayMetrics().density);
        provider.setPadding(padding, padding, padding, padding);
        provider.addView(webView, new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                (int) (getResources().getDisplayMetrics().heightPixels * 0.8)
        ));

        webView.loadUrl(PRIVACY_URL);

        privacyDialog = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK) // 强制使用暗色主题
                .setTitle("用户协议与隐私政策")
                .setView(provider)
                .setCancelable(false)
                .setPositiveButton("同意", null) // 后面再设置监听,防止点击即消失
                .setNegativeButton("拒绝并退出", (dialog, which) -> {
                    finishAffinity();
                    System.exit(0);
                })
                .create();

        privacyDialog.setCanceledOnTouchOutside(false);
        privacyDialog.setOnKeyListener((d, keyCode, event) -> keyCode == KeyEvent.KEYCODE_BACK);

        privacyDialog.show();

        // 获取按钮并启动倒计时逻辑
        positiveButton = privacyDialog.getButton(DialogInterface.BUTTON_POSITIVE);
        positiveButton.setEnabled(false);
        positiveButton.setOnClickListener(v -> {
            getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit().putBoolean(KEY_ACCEPTED, true).apply();
            privacyDialog.dismiss();
            startRenPyGame();
        });

        startCountdownTimer();
    }

    private void startCountdownTimer() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (isFinishing() || isDestroyed()) return;
                if (countdown > 0) {
                    positiveButton.setText("同意 (" + countdown + "s)");
                    countdown--;
                    handler.postDelayed(this, 1000);
                } else {
                    positiveButton.setText("同意");
                    positiveButton.setEnabled(true);
                }
            }
        });
    }

    private void startRenPyGame() {
        try {
            Intent intent = new Intent(this, Class.forName("org.renpy.android.PythonSDLActivity"));
            startActivity(intent);
            finish();
            // 彻底移除转场动画,防止白光闪烁
            overridePendingTransition(0, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onBackPressed() {
        // 禁用物理返回键
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);
        if (privacyDialog != null && privacyDialog.isShowing()) {
            privacyDialog.dismiss();
        }
    }
}

 

这两个文件弄完就OK了,里面的百度链接是占位符,生产直接改为对应隐私政策地址即可

然后就是尽量不要点 RenPy Launcher 安卓子菜单中的【强制重新编译】,你一点,这俩类会被回滚,到时候你还得重新操作。不过有的时候修bug/调试时,是需要强制重新编译,只能届时再重新替换代码,反正只要打包前替换,最终提交生产环境的apk是正常的就行。

 

 

           


CAPTCHAis initialing...