[CocosCreator]Android的增加AndroidX的动态权限

         欢迎喜欢或者从事CocosCreator开发的小伙伴请加入我的大家庭CocosCreator游戏开发Q群:26855530

1.首先增加你需要申请的权限,修改:AndroidManifest.xml:

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

    <uses-feature android:glEsVersion="0x00020000" />

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

<!--    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
<!--    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />-->
    <!-- Android 13 特殊权限 -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:usesCleartextTraffic="true"
        android:icon="@mipmap/ic_launcher"
        android:supportsRtl="true">
        <!-- Tell Cocos2dxActivity the name of our .so -->
        <meta-data android:name="android.app.lib_name"
                   android:value="cocos2djs" />
        
        <activity
            android:name="org.cocos2dx.javascript.AppActivity"
            android:screenOrientation="sensorLandscape"
            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout|uiMode"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:launchMode="singleTask"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2. 确保你使用的是AndroidX

确保项目的 gradle.properties 文件中包含如下配置:

# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

# Android SDK version that will be used as the compile project
PROP_COMPILE_SDK_VERSION=33

# Android SDK version that will be used as the earliest version of android this application can run on
PROP_MIN_SDK_VERSION=26

# Android SDK version that will be used as the latest version of android this application has been tested on
PROP_TARGET_SDK_VERSION=33

# Android Build Tools version that will be used as the compile project
PROP_BUILD_TOOLS_VERSION=28.0.3

# List of CPU Archtexture to build that application with
# Available architextures (armeabi-v7a | arm64-v8a | x86)
# To build for multiple architexture, use the `:` between them
# Example - PROP_APP_ABI=armeabi-v7a:arm64-v8a:x86_64
PROP_APP_ABI=armeabi-v7a:arm64-v8a:x86_64

# fill in sign information for release mode
RELEASE_STORE_FILE=/Applications/Cocos/Creator/2.4.10/CocosCreator.app/Contents/Resources/static/build-templates/native/debug.keystore
RELEASE_STORE_PASSWORD=123456
RELEASE_KEY_ALIAS=debug_keystore
RELEASE_KEY_PASSWORD=123456

android.injected.testOnly=false

# android.enableJetifier=true

android.useAndroidX=true
android.enableJetifier=true

3. 更新 build.gradle 文件

在你的项目的 build.gradle 文件中,确保包含了AndroidX库的依赖项:

import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()
    buildToolsVersion PROP_BUILD_TOOLS_VERSION

    defaultConfig {
        applicationId "com.zhcj.xzjh"
        minSdkVersion PROP_MIN_SDK_VERSION
        targetSdkVersion PROP_TARGET_SDK_VERSION
        versionCode 1
        versionName "1.0"

        externalNativeBuild {
            ndkBuild {
                if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
                    // skip the NDK Build step if PROP_NDK_MODE is none
                    targets 'cocos2djs'
                    arguments 'NDK_TOOLCHAIN_VERSION=clang'

                    def module_paths = [project.file("../../../cocos2d-x"),
                                        project.file("../../../cocos2d-x/cocos"),
                                        project.file("../../../cocos2d-x/external")]
                    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                        arguments 'NDK_MODULE_PATH=' + module_paths.join(";")
                    }
                    else {
                        arguments 'NDK_MODULE_PATH=' + module_paths.join(':')
                    }
                    
                    arguments '-j' + Runtime.runtime.availableProcessors()
                }
            }
            ndk {
                abiFilters PROP_APP_ABI.split(':')
            }
        }
    }

    sourceSets.main {
        java.srcDirs "../src", "src"
        res.srcDirs "../res", 'res'
        jniLibs.srcDirs "../libs", 'libs'
        manifest.srcFile "AndroidManifest.xml"
    }

    externalNativeBuild {
        ndkBuild {
            if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
                // skip the NDK Build step if PROP_NDK_MODE is none
                path "jni/Android.mk"
            }
        }
    }

    signingConfigs {

       release {
            if (project.hasProperty("RELEASE_STORE_FILE")) {
                storeFile file(RELEASE_STORE_FILE)
                storePassword RELEASE_STORE_PASSWORD
                keyAlias RELEASE_KEY_ALIAS
                keyPassword RELEASE_KEY_PASSWORD
            }
        }
    }

    buildTypes {
        release {
            debuggable false
            jniDebuggable false
            renderscriptDebuggable false
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            if (project.hasProperty("RELEASE_STORE_FILE")) {
                signingConfig signingConfigs.release
            }

            externalNativeBuild {
                ndkBuild {
                    arguments 'NDK_DEBUG=0'
                }
            }
        }

        debug {
            debuggable true
            jniDebuggable true
            renderscriptDebuggable true
            externalNativeBuild {
                ndkBuild {
                    arguments 'NDK_DEBUG=1'
                }
            }
        }
    }
}

android.applicationVariants.all { variant ->
    // delete previous files first
    delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"

    variant.mergeAssets.doLast {
        def sourceDir = "${buildDir}/../../../../.."

        copy {
            from "${sourceDir}"
            include "assets/**"
            include "src/**"
            include "jsb-adapter/**"
            into outputDir
        }

        copy {
            from "${sourceDir}/main.js"
            from "${sourceDir}/project.json"
            into outputDir
        }
    }
}

dependencies {
    implementation fileTree(dir: '../libs', include: ['*.jar','*.aar'])
    implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
    implementation fileTree(dir: "../../../cocos2d-x/cocos/platform/android/java/libs", include: ['*.jar'])
    implementation project(':libcocos2dx')

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

    implementation 'androidx.core:core-ktx:1.10.1'
    implementation 'androidx.appcompat:appcompat:1.6.1'
}

确保在项目级别的 build.gradle 文件中包含Google的Maven仓库:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext.kotlin_version = '1.8.10' // 确保使用最新的 Kotlin 版本
    repositories {
        google()
        jcenter()
    }
    dependencies {

//        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath 'com.android.tools.build:gradle:7.4.2' // Android Gradle 插件版本
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"


        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
                dirs 'libs'
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

两外附上一个监听网络工具类:

package org.cocos2dx.javascript.utils;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkInfo;
import android.os.Build;

public class NetworkUtil {

    private Context context;

    public NetworkUtil(Context context) {
        this.context = context;
    }

    public boolean isWiFiAvailable() {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnected() && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
    }

    public void useWiFiThenMobile(final NetworkCallback callback) {
        final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);

        cm.registerNetworkCallback(builder.build(), new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                // WiFi is available
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    cm.bindProcessToNetwork(network);
                } else {
                    ConnectivityManager.setProcessDefaultNetwork(network);
                }
                callback.onNetworkSelected(true);
            }

            @Override
            public void onUnavailable() {
                // WiFi is not available, use mobile data
                cm.unregisterNetworkCallback(this);
                useMobileData(callback);
            }
        });
    }

    private void useMobileData(NetworkCallback callback) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);

        cm.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                // Mobile data is available
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    cm.bindProcessToNetwork(network);
                } else {
                    ConnectivityManager.setProcessDefaultNetwork(network);
                }
                callback.onNetworkSelected(false);
            }
        });
    }

    public interface NetworkCallback {
        void onNetworkSelected(boolean isWiFi);
    }
}

主角登场AppActivity.java:

package org.cocos2dx.javascript;

import org.cocos2dx.javascript.utils.NetworkUtil;
import org.cocos2dx.lib.Cocos2dxActivity;
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;

import android.os.Bundle;

import android.content.Intent;
import android.content.res.Configuration;

import android.Manifest;

import android.content.pm.PackageManager;
import android.os.Build;

import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class AppActivity extends Cocos2dxActivity {

    private static final int PERMISSION_REQUEST_CODE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // DO OTHER INITIALIZATION BELOW
        SDKWrapper.getInstance().init(this);

        // 检查并请求权限
        checkAndRequestPermissions();
    }

    private void checkAndRequestPermissions() {
        boolean internetPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED;
        boolean networkStatePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED;
        boolean wifiStatePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE) == PackageManager.PERMISSION_GRANTED;
//            boolean readStoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
//            boolean writeStoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13
            boolean notificationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
            if (!notificationPermission || !internetPermission || !networkStatePermission || !wifiStatePermission
                    //|| !readStoragePermission || !writeStoragePermission
            ) {
                ActivityCompat.requestPermissions(this, new String[]{
                        Manifest.permission.INTERNET,
                        Manifest.permission.ACCESS_NETWORK_STATE,
                        Manifest.permission.ACCESS_WIFI_STATE,
                        //Manifest.permission.READ_EXTERNAL_STORAGE,
                        //Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.POST_NOTIFICATIONS
                }, PERMISSION_REQUEST_CODE);
            }
        } else {
            if (!internetPermission || !networkStatePermission || !wifiStatePermission
                    //|| !readStoragePermission || !writeStoragePermission
            ) {
                ActivityCompat.requestPermissions(this, new String[]{
                        Manifest.permission.INTERNET,
                        Manifest.permission.ACCESS_NETWORK_STATE,
                        Manifest.permission.ACCESS_WIFI_STATE,
//                            Manifest.permission.READ_EXTERNAL_STORAGE,
//                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                }, PERMISSION_REQUEST_CODE);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            boolean allPermissionsGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allPermissionsGranted = false;
                    break;
                }
            }

            if (allPermissionsGranted) {
//                Toast.makeText(this, "所有权限已授予", Toast.LENGTH_SHORT).show();
                initializeNetworkUtil();
            } else {
                Toast.makeText(this, "权限被拒绝,程序即将关闭", Toast.LENGTH_SHORT).show();
                finish();  // 关闭程序

                //另一种关闭程序方式
//                finishAffinity();
//                System.exit(0);
            }
        }
    }

    private void initializeNetworkUtil() {
        NetworkUtil networkUtil = new NetworkUtil(this);
        networkUtil.useWiFiThenMobile(isWiFi -> {
            // Do something based on network selection
            if (isWiFi) {
                Log.d("NetworkUtil", "Connected to WiFi. Starting download service...");
//                startDownloadService();
            } else {
                // 用户已连接到移动数据网络
                // 可以提示用户注意流量消耗
                Log.d("NetworkUtil", "Connected to mobile data. Be cautious of data usage.");
                showMobileDataWarning();
            }
        });
    }

    private void showMobileDataWarning() {
        // 显示移动数据警告的代码
    }

    @Override
    public Cocos2dxGLSurfaceView onCreateView() {
        Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
        // TestCpp should create stencil buffer
        glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8);
        SDKWrapper.getInstance().setGLSurfaceView(glSurfaceView, this);

        return glSurfaceView;
    }

    @Override
    protected void onResume() {
        super.onResume();
        SDKWrapper.getInstance().onResume();
        // 每次恢复活动时,检查权限是否被授予
        boolean internetPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED;
        boolean networkStatePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED;
        boolean wifiStatePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE) == PackageManager.PERMISSION_GRANTED;
//            boolean readStoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
//            boolean writeStoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;

        //                        || !readStoragePermission || !writeStoragePermission
        // 重新请求权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13
            boolean notificationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
        }
        if (!internetPermission || !networkStatePermission || !wifiStatePermission
//                        || !readStoragePermission || !writeStoragePermission || !notificationPermission
        ) {
            checkAndRequestPermissions();  // 重新请求权限
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        SDKWrapper.getInstance().onPause();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
        if (!isTaskRoot()) {
            return;
        }

        SDKWrapper.getInstance().onDestroy();

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        SDKWrapper.getInstance().onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        SDKWrapper.getInstance().onNewIntent(intent);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        SDKWrapper.getInstance().onRestart();
    }

    @Override
    protected void onStop() {
        super.onStop();
        SDKWrapper.getInstance().onStop();
    }

    @Override
    public void onBackPressed() {
        SDKWrapper.getInstance().onBackPressed();
        super.onBackPressed();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        SDKWrapper.getInstance().onConfigurationChanged(newConfig);
        super.onConfigurationChanged(newConfig);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        SDKWrapper.getInstance().onRestoreInstanceState(savedInstanceState);
        super.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        SDKWrapper.getInstance().onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onStart() {
        SDKWrapper.getInstance().onStart();
        super.onStart();
    }
}

然后就ok,打包拉~

补上我项目的ndk版本:26.3.11579264

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Artemis丶月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值