+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cocos.game;
+
+//import android.app.NotificationChannel;
+//import android.app.NotificationManager;
+//import android.app.PendingIntent;
+//import android.content.Context;
+//import android.content.Intent;
+//import android.media.RingtoneManager;
+//import android.net.Uri;
+//import android.os.Build;
+//import androidx.core.app.NotificationCompat;
+
+import android.util.Log;
+
+import com.adjust.sdk.Adjust;
+import com.google.android.gms.common.GoogleApiAvailability;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+//import com.google.firebase.quickstart.fcm.R;
+//
+//import androidx.work.OneTimeWorkRequest;
+//import androidx.work.WorkManager;
+
+/**
+ * NOTE: There can only be one service in each app that receives FCM messages. If multiple
+ * are declared in the Manifest then the first one will be chosen.
+ *
+ * In order to make this Java sample functional, you must remove the following from the Kotlin messaging
+ * service in the AndroidManifest.xml:
+ *
+ *
+ *
+ *
+ */
+public class MyFirebaseMessagingService extends FirebaseMessagingService {
+
+ private static final String TAG = "MyFirebaseMsgService";
+
+ /**
+ * Called when message is received.
+ *
+ * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
+ */
+ // [START receive_message]
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ // [START_EXCLUDE]
+ // There are two types of messages data messages and notification messages. Data messages
+ // are handled
+ // here in onMessageReceived whether the app is in the foreground or background. Data
+ // messages are the type
+ // traditionally used with GCM. Notification messages are only received here in
+ // onMessageReceived when the app
+ // is in the foreground. When the app is in the background an automatically generated
+ // notification is displayed.
+ // When the user taps on the notification they are returned to the app. Messages
+ // containing both notification
+ // and data payloads are treated as notification messages. The Firebase console always
+ // sends notification
+ // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
+ // [END_EXCLUDE]
+
+ // TODO(developer): Handle FCM messages here.
+ // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
+ Log.d(TAG, "From: " + remoteMessage.getFrom());
+
+// // Check if message contains a data payload.
+// if (remoteMessage.getData().size() > 0) {
+// Log.d(TAG, "Message data payload: " + remoteMessage.getData());
+//
+// if (/* Check if data needs to be processed by long running job */ true) {
+// // For long-running tasks (10 seconds or more) use WorkManager.
+// scheduleJob();
+// } else {
+// // Handle message within 10 seconds
+// handleNow();
+// }
+//
+// }
+
+ // Check if message contains a notification payload.
+ if (remoteMessage.getNotification() != null) {
+ Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
+ }
+
+ // Also if you intend on generating your own notifications as a result of a received FCM
+ // message, here is where that should be initiated. See sendNotification method below.
+ }
+ // [END receive_message]
+
+
+ // [START on_new_token]
+
+ /**
+ * There are two scenarios when onNewToken is called:
+ * 1) When a new token is generated on initial app startup
+ * 2) Whenever an existing token is changed
+ * Under #2, there are three scenarios when the existing token is changed:
+ * A) App is restored to a new device
+ * B) User uninstalls/reinstalls the app
+ * C) User clears app data
+ */
+ @Override
+ public void onNewToken(String token) {
+ Log.d(TAG, "Refreshed token: " + token);
+ Adjust.setPushToken(token, getApplicationContext());
+
+ // If you want to send messages to this application instance or
+ // manage this apps subscriptions on the server side, send the
+ // FCM registration token to your app server.
+// sendRegistrationToServer(token);
+
+ }
+ // [END on_new_token]
+
+// /**
+// * Schedule async work using WorkManager.
+// */
+// private void scheduleJob() {
+// // [START dispatch_job]
+// OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(MyWorker.class)
+// .build();
+// WorkManager.getInstance(this).beginWith(work).enqueue();
+// // [END dispatch_job]
+// }
+
+ /**
+ * Handle time allotted to BroadcastReceivers.
+ */
+ private void handleNow() {
+ Log.d(TAG, "Short lived task is done.");
+ }
+
+ /**
+ * Persist token to third-party servers.
+ *
+ * Modify this method to associate the user's FCM registration token with any
+ * server-side account maintained by your application.
+ *
+ * @param token The new token.
+ */
+ private void sendRegistrationToServer(String token) {
+ // TODO: Implement this method to send token to your app server.
+ }
+
+// /**
+// * Create and show a simple notification containing the received FCM message.
+// *
+// * @param messageBody FCM message body received.
+// */
+// private void sendNotification(String messageBody) {
+// Intent intent = new Intent(this, MainActivity.class);
+// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+// PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
+// PendingIntent.FLAG_ONE_SHOT);
+//
+// String channelId = getString(R.string.default_notification_channel_id);
+// Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+// NotificationCompat.Builder notificationBuilder =
+// new NotificationCompat.Builder(this, channelId)
+// .setSmallIcon(R.drawable.ic_stat_ic_notification)
+// .setContentTitle(getString(R.string.fcm_message))
+// .setContentText(messageBody)
+// .setAutoCancel(true)
+// .setSound(defaultSoundUri)
+// .setContentIntent(pendingIntent);
+//
+// NotificationManager notificationManager =
+// (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+//
+// // Since android Oreo notification channel is needed.
+// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+// NotificationChannel channel = new NotificationChannel(channelId,
+// "Channel human readable title",
+// NotificationManager.IMPORTANCE_DEFAULT);
+// notificationManager.createNotificationChannel(channel);
+// }
+//
+// notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
+// }
+}
\ No newline at end of file
diff --git a/android/app/src/com/cocos/game/PermissionsUtil.java b/android/app/src/com/cocos/game/PermissionsUtil.java
new file mode 100644
index 0000000..7be7ff4
--- /dev/null
+++ b/android/app/src/com/cocos/game/PermissionsUtil.java
@@ -0,0 +1,547 @@
+package com.cocos.game;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+/**
+ * 动态申请权限工具类
+ */
+
+public class PermissionsUtil {
+
+ private PermissionsUtil() {
+ }
+
+ /**
+ * 危险权限,targetSdkVersion >=23必须动态申请
+ */
+ public static final class Permission {
+ private static final List sCalendars = new ArrayList(2);
+ private static final List sCameras = new ArrayList(1);
+ private static final List sContactes = new ArrayList(3);
+ private static final List sLocations = new ArrayList(2);
+ private static final List sMicrophones = new ArrayList(1);
+ private static final List sPhones = new ArrayList(7);
+ private static final List sSensorses = new ArrayList(1);
+ private static final List sSmses = new ArrayList(5);
+ private static final List sStorages = new ArrayList(2);
+
+ static {
+ //Calendar
+ sCalendars.add(Calendar.READ_CALENDAR);
+ sCalendars.add(Calendar.WRITE_CALENDAR);
+ //Camera
+ sCameras.add(Camera.CAMERA);
+ //Contacts
+ sContactes.add(Contacts.WRITE_CONTACTS);
+ sContactes.add(Contacts.READ_CONTACTS);
+ sContactes.add(Contacts.GET_ACCOUNTS);
+ //Location
+ sLocations.add(Location.ACCESS_FINE_LOCATION);
+ sLocations.add(Location.ACCESS_COARSE_LOCATION);
+ //Microphone
+ sMicrophones.add(Microphone.RECORD_AUDIO);
+ //Phone
+ sPhones.add(Phone.READ_PHONE_STATE);
+ sPhones.add(Phone.CALL_PHONE);
+ sPhones.add(Phone.READ_CALL_LOG);
+ sPhones.add(Phone.WRITE_CALL_LOG);
+ sPhones.add(Phone.ADD_VOICEMAIL);
+ sPhones.add(Phone.USE_SIP);
+ sPhones.add(Phone.PROCESS_OUTGOING_CALLS);
+ //Sensors
+ sSensorses.add(Sensors.BODY_SENSORS);
+ //Sms
+ sSmses.add(Sms.SEND_SMS);
+ sSmses.add(Sms.RECEIVE_SMS);
+ sSmses.add(Sms.READ_SMS);
+ sSmses.add(Sms.RECEIVE_WAP_PUSH);
+ sSmses.add(Sms.RECEIVE_MMS);
+ //Storage
+ sStorages.add(Storage.READ_EXTERNAL_STORAGE);
+ sStorages.add(Storage.WRITE_EXTERNAL_STORAGE);
+ }
+
+ public static final class Calendar {
+ public static final String READ_CALENDAR = Manifest.permission.READ_CALENDAR;
+ public static final String WRITE_CALENDAR = Manifest.permission.WRITE_CALENDAR;
+ private static final String MSG = "日历";
+ }
+
+ public static final class Camera {
+ public static final String CAMERA = Manifest.permission.CAMERA;
+ private static final String MSG = "kamera";//相机
+ }
+
+ public static final class Contacts {
+ public static final String READ_CONTACTS = Manifest.permission.READ_CONTACTS;
+ public static final String WRITE_CONTACTS = Manifest.permission.WRITE_CONTACTS;
+ public static final String GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;
+ private static final String MSG = "联系人";
+ }
+
+ public static final class Location {
+ public static final String ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
+ public static final String ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
+ private static final String MSG = "定位";
+ }
+
+ public static final class Microphone {
+ public static final String RECORD_AUDIO = Manifest.permission.RECORD_AUDIO;
+ private static final String MSG = "mikrofon";//麦克风
+ }
+
+ public static final class Phone {
+ public static final String READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;
+ public static final String CALL_PHONE = Manifest.permission.CALL_PHONE;
+ public static final String READ_CALL_LOG = Manifest.permission.READ_CALL_LOG;
+ public static final String WRITE_CALL_LOG = Manifest.permission.WRITE_CALL_LOG;
+ public static final String ADD_VOICEMAIL = Manifest.permission.ADD_VOICEMAIL;
+ public static final String USE_SIP = Manifest.permission.USE_SIP;
+ public static final String PROCESS_OUTGOING_CALLS = Manifest.permission.PROCESS_OUTGOING_CALLS;
+ private static final String MSG = "电话";
+ }
+
+ public static final class Sensors {
+ public static final String BODY_SENSORS = Manifest.permission.BODY_SENSORS;
+ private static final String MSG = "传感器";
+ }
+
+
+ public static final class Sms {
+ public static final String SEND_SMS = Manifest.permission.SEND_SMS;
+ public static final String RECEIVE_SMS = Manifest.permission.RECEIVE_SMS;
+ public static final String READ_SMS = Manifest.permission.READ_SMS;
+ public static final String RECEIVE_WAP_PUSH = Manifest.permission.RECEIVE_WAP_PUSH;
+ public static final String RECEIVE_MMS = Manifest.permission.RECEIVE_MMS;
+ private static final String MSG = "短信";
+ }
+
+ public static final class Storage {
+ public static final String READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
+ public static final String WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+ public static final String CAMERA = Manifest.permission.CAMERA;
+ private static final String MSG = "Hafıza";//存储
+ }
+ }
+
+ public static final int SETTINGS_REQ_CODE = 99;
+ private static final String TAG = "PermissionsUtil";
+ private static final String KEY_DENIED_PERMISSIONS = "deniedPermissions";
+ private static final String KEY_REQUEST_CODE = "requestCode";
+ private static final int MSG_UI_HANDLER_DEAL_DENIED_PERMISSION = 100;
+ private static boolean sDebug = true;
+ private Object mObject;
+ private String[] mPermissions;
+ private int mRequestCode;
+ private String mRationaleTitle;
+ private String mPositiveText = "Emin ol";//确定
+ private String mNegativeText = "İptal";//取消
+ private int mRequestPermissionCount = 0;//请求授权次数
+ private Handler mUiHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UI_HANDLER_DEAL_DENIED_PERMISSION:
+ Bundle data = msg.getData();
+ int requestCode = data.getInt(KEY_REQUEST_CODE);
+ String[] permissions = data.getStringArray(KEY_DENIED_PERMISSIONS);
+ Object object = msg.obj;
+ showAlertDialog(object, requestCode, permissions);
+ break;
+ }
+ }
+ };
+
+
+ private PermissionsUtil(@NonNull Object object) {
+ if (isObjectIllegality(object))
+ throw new IllegalArgumentException("Activity or Fragment must implements IPermissionsCallback");
+ mObject = object;
+ }
+
+ public static PermissionsUtil with(@NonNull Activity activity) {
+ return new PermissionsUtil(activity);
+ }
+
+ public static PermissionsUtil with(@NonNull Fragment fragment) {
+ return new PermissionsUtil(fragment);
+ }
+
+ public static PermissionsUtil with(@NonNull android.app.Fragment fragment) {
+ return new PermissionsUtil(fragment);
+ }
+
+ public PermissionsUtil permissions(@NonNull String... permissions) {
+ if (hasEmpty(permissions))
+ throw new IllegalArgumentException("permissions can't contain null");
+ mPermissions = permissions;
+ return this;
+ }
+
+ public PermissionsUtil requestCode(int requestCode) {
+ mRequestCode = requestCode;
+ return this;
+ }
+
+ public PermissionsUtil rationaleTitle(String title) {
+ mRationaleTitle = title;
+ return this;
+ }
+
+ public PermissionsUtil positiveText(String positiveText) {
+ mPositiveText = positiveText;
+ return this;
+ }
+
+ public PermissionsUtil negativeText(String negativeText) {
+ mNegativeText = negativeText;
+ return this;
+ }
+
+ public PermissionsUtil isDebug(boolean isDebug) {
+ sDebug = isDebug;
+ return this;
+ }
+
+ public PermissionsUtil requestPermissionCount(int requestPermissionCount) {
+ mRequestPermissionCount = requestPermissionCount;
+ return this;
+ }
+
+ public PermissionsUtil request() {
+ request(mObject, mRequestCode, mPermissions);
+ return this;
+ }
+
+ public void request(Object object, int requestCode, String... permissions) {
+ if (needRequest() && notGrantedAllPermissions(getActivity(object), permissions)) {
+ if (mRequestPermissionCount > 2) {
+ dealDeniedPermissions(object, requestCode, permissions);
+ } else {
+ List unGrantedPermissionsList = createUnGrantedPermissionsList(object, permissions);
+ PLog.d("request---" + "requestCode : " + requestCode + "---unGrantedPermissionsList : " + unGrantedPermissionsList);
+ if (unGrantedPermissionsList.size() > 0) {
+ requestPermissions(object, requestCode, listToStringArray(unGrantedPermissionsList));
+ unGrantedPermissionsList.clear();
+ } else {
+ invokePermissionsGranted(object, requestCode, permissions);
+ }
+ unGrantedPermissionsList = null;
+ }
+ } else {
+ PLog.d("request---" + "requestCode : " + requestCode + "---permissionsGranted : " + stringArrayToList(permissions));
+ invokePermissionsGranted(object, requestCode, permissions);
+ }
+ }
+
+ private List createUnGrantedPermissionsList(Object object, String... permissions) {
+ List unGrantedPermissionsList = new ArrayList();
+ for (String permission : permissions) {
+ if (notGrantedPermission(getActivity(object), permission)) {
+ unGrantedPermissionsList.add(permission);
+ }
+ }
+ return unGrantedPermissionsList;
+ }
+
+
+ @SuppressLint("NewApi")
+ private void requestPermissions(Object object, int requestCode, String... permissions) {
+ PLog.d("requestPermissions---" + "requestCode : " + requestCode + "---requestPermissions : " + stringArrayToList(permissions));
+ if (object instanceof Activity) {
+ ActivityCompat.requestPermissions((Activity) object, permissions, requestCode);
+ } else if (object instanceof Fragment) {
+ ((Fragment) object).requestPermissions(permissions, requestCode);
+ } else if (object instanceof android.app.Fragment) {
+ ((android.app.Fragment) object).requestPermissions(permissions, requestCode);
+ }
+ }
+
+ /**
+ * @param object
+ * @param requestCode
+ * @param deniedPermissions denied permissions
+ * @return
+ */
+ private void showAlertDialog(final Object object, final int requestCode, final String... deniedPermissions) {
+ PLog.d("showAlertDialog --- " + "requestCode : " + requestCode + "--- deniedPermissions : " + stringArrayToList(deniedPermissions));
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(mObject));
+ if (!TextUtils.isEmpty(mRationaleTitle)) {
+ builder.setTitle(mRationaleTitle);
+ }
+ builder.setMessage(createRationaleMsg(getActivity(object), deniedPermissions))
+ .setPositiveButton(mPositiveText, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ goSetting(object);
+ }
+
+
+ })
+ .setNegativeButton(mNegativeText, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ invokePermissionsDenied(object, requestCode, deniedPermissions);
+ }
+ })
+ .create()
+ .show();
+ }
+
+ private boolean needRequest() {
+ return Build.VERSION.SDK_INT >= 23;
+ }
+
+ private Activity getActivity(Object object) {
+ Activity activity = null;
+ if (object instanceof Activity) {
+ activity = (Activity) object;
+ } else if (object instanceof Fragment) {
+ activity = ((Fragment) object).getActivity();
+ } else if (object instanceof android.app.Fragment) {
+ activity = ((android.app.Fragment) object).getActivity();
+ }
+ return activity;
+ }
+
+ public boolean grantedPermission(Activity activity, String permission) {
+ return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ public boolean notGrantedPermission(Activity activity, String permission) {
+ return !grantedPermission(activity, permission);
+ }
+
+ public boolean grantedAllPermissions(Activity activity, String... permissions) {
+ for (String permission : permissions) {
+ if (notGrantedPermission(activity, permission)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean notGrantedAllPermissions(Activity activity, String... permissions) {
+ return !grantedAllPermissions(activity, permissions);
+ }
+
+ private void dealDeniedPermissions(Object object, int requestCode, String... deniedPermissions) {
+ PLog.d("dealDeniedPermissions --- " + "requestCode : " + requestCode + "--- deniedPermissions : " + stringArrayToList(deniedPermissions));
+ Message message = mUiHandler.obtainMessage();
+ Bundle bundle = new Bundle();
+ bundle.putStringArray(KEY_DENIED_PERMISSIONS, deniedPermissions);
+ bundle.putInt(KEY_REQUEST_CODE, requestCode);
+ message.setData(bundle);
+ message.obj = object;
+ message.what = MSG_UI_HANDLER_DEAL_DENIED_PERMISSION;
+ mUiHandler.sendMessage(message);
+ }
+
+ private boolean isObjectLegal(Object object) {
+ return (object instanceof IPermissionsCallback);
+ }
+
+ private boolean isObjectIllegality(Object object) {
+ return !isObjectLegal(object);
+ }
+
+ private boolean hasEmpty(String... strings) {
+ boolean hasEmpty = false;
+ if (strings != null && strings.length > 0) {
+ for (String s : strings) {
+ if (TextUtils.isEmpty(s)) {
+ hasEmpty = true;
+ break;
+ }
+ }
+ } else {
+ hasEmpty = true;
+ }
+ return hasEmpty;
+ }
+
+ private String[] listToStringArray(List stringList) {
+ return stringList.toArray(new String[stringList.size()]);
+ }
+
+ private List stringArrayToList(String[] strings) {
+ return Arrays.asList(strings);
+ }
+
+ private String getAppName(Context context) {
+ String appName = "";
+ PackageManager packageManager = context.getPackageManager();
+ try {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
+ appName = (String) packageManager.getApplicationLabel(applicationInfo);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return appName;
+ }
+
+ private String createRationaleMsg(Context context, String... permissions) {
+ String permissionsMsg = createPermissionsMsg(permissions);
+ permissionsMsg = permissionsMsg.substring(0, permissionsMsg.length() - 1);
+ // return getAppName(context) + "需要" + permissionsMsg + "权限,是否去设置";
+ return getAppName(context) + permissionsMsg + " iznine ihtiyacınız var,ayarlanıp ayarlanmayacağı?";
+ }
+
+ private String createPermissionsMsg(String... permissions) {
+ StringBuilder builder = new StringBuilder();
+ boolean grantedCalendar = false;
+ boolean grantedCamera = false;
+ boolean grantedContacts = false;
+ boolean grantedLocation = false;
+ boolean grantedMicrophone = false;
+ boolean grantedPhone = false;
+ boolean grantedSensors = false;
+ boolean grantedSms = false;
+ boolean grantedStorage = false;
+ for (String permission : permissions) {
+ if (!grantedCalendar && Permission.sCalendars.contains(permission)) {
+ builder.append(Permission.Calendar.MSG);
+ builder.append("、");
+ grantedCalendar = true;
+ }
+ if (!grantedCamera && Permission.sCameras.contains(permission)) {
+ builder.append(Permission.Camera.MSG);
+ builder.append("、");
+ grantedCamera = true;
+ }
+ if (!grantedContacts && Permission.sContactes.contains(permission)) {
+ builder.append(Permission.Contacts.MSG);
+ builder.append("、");
+ grantedContacts = true;
+ }
+ if (!grantedLocation && Permission.sLocations.contains(permission)) {
+ builder.append(Permission.Location.MSG);
+ builder.append("、");
+ grantedLocation = true;
+ }
+ if (!grantedMicrophone && Permission.sMicrophones.contains(permission)) {
+ builder.append(Permission.Microphone.MSG);
+ builder.append("、");
+ grantedMicrophone = true;
+ }
+ if (!grantedPhone && Permission.sPhones.contains(permission)) {
+ builder.append(Permission.Phone.MSG);
+ builder.append("、");
+ grantedPhone = true;
+ }
+ if (!grantedSensors && Permission.sSensorses.contains(permission)) {
+ builder.append(Permission.Sensors.MSG);
+ builder.append("、");
+ grantedSensors = true;
+ }
+ if (!grantedSms && Permission.sSmses.contains(permission)) {
+ builder.append(Permission.Sms.MSG);
+ builder.append("、");
+ grantedSms = true;
+ }
+ if (!grantedStorage && Permission.sStorages.contains(permission)) {
+ builder.append(Permission.Storage.MSG);
+ builder.append("、");
+ grantedStorage = true;
+ }
+ }
+ return builder.toString();
+ }
+
+ private IPermissionsCallback getPermissionsCallback(Object object) {
+ return (IPermissionsCallback) object;
+ }
+
+ private void invokePermissionsGranted(Object object, int requestCode, String... permissions) {
+ getPermissionsCallback(object).onPermissionsGranted(requestCode, permissions);
+ }
+
+ private void invokePermissionsDenied(Object object, int requestCode, String... permissions) {
+ getPermissionsCallback(object).onPermissionsDenied(requestCode, permissions);
+ }
+
+ public interface IPermissionsCallback {
+ void onPermissionsGranted(int requestCode, String... permission);
+
+ void onPermissionsDenied(int requestCode, String... permission);
+ }
+
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode == mRequestCode) {
+ List deniedPermissions = new ArrayList();
+ for (int i = 0; i < grantResults.length; i++) {
+ if (grantResults[i] != PackageManager.PERMISSION_GRANTED)
+ deniedPermissions.add(permissions[i]);
+ }
+ PLog.d("onRequestPermissionsResult--- " + "requestCode : " + requestCode + "--- deniedPermissions : " + deniedPermissions);
+ if (deniedPermissions.size() > 0) {
+ dealDeniedPermissions(mObject, requestCode, listToStringArray(deniedPermissions));
+ } else {
+ invokePermissionsGranted(mObject, requestCode, permissions);
+ }
+ }
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == SETTINGS_REQ_CODE) {
+ List unGrantedPermissionsList = createUnGrantedPermissionsList(mObject, mPermissions);
+ PLog.d("onActivityResult --- " + "requestCode : " + requestCode + "---" + "unGrantedPermissionsList : " + unGrantedPermissionsList);
+ if (unGrantedPermissionsList.size() > 0) {
+ invokePermissionsDenied(mObject, mRequestCode, listToStringArray(unGrantedPermissionsList));
+ } else {
+ invokePermissionsGranted(mObject, mRequestCode, mPermissions);
+ }
+ }
+ }
+
+ private void goSetting(Object object) {
+ PLog.d("goSetting");
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Uri uri = Uri.fromParts("package", getActivity(object).getPackageName(), null);
+ intent.setData(uri);
+ if (object instanceof Activity) {
+ ((Activity) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
+ } else if (object instanceof Fragment) {
+ ((Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
+ } else if (object instanceof android.app.Fragment) {
+ ((android.app.Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
+ }
+ }
+
+ static final class PLog {
+ private static void d(String msg) {
+ if (sDebug)
+ Log.d(TAG, msg);
+ }
+
+ private static void e(String msg) {
+ if (sDebug)
+ Log.e(TAG, msg);
+ }
+ }
+}
diff --git a/android/app/src/com/cocos/game/PictureSelectlucksiege.java b/android/app/src/com/cocos/game/PictureSelectlucksiege.java
new file mode 100644
index 0000000..fd0cbe0
--- /dev/null
+++ b/android/app/src/com/cocos/game/PictureSelectlucksiege.java
@@ -0,0 +1,406 @@
+package com.cocos.game;
+
+import android.Manifest;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.CustomTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.luck.lib.camerax.CameraImageEngine;
+import com.luck.lib.camerax.SimpleCameraX;
+import com.luck.picture.lib.config.PictureMimeType;
+import com.luck.picture.lib.config.SelectLimitType;
+import com.luck.picture.lib.config.SelectorConfig;
+import com.luck.picture.lib.dialog.RemindDialog;
+import com.luck.picture.lib.engine.CompressFileEngine;
+import com.luck.picture.lib.engine.CropFileEngine;
+import com.luck.picture.lib.engine.UriToFileTransformEngine;
+import com.luck.picture.lib.entity.LocalMedia;
+import com.luck.picture.lib.interfaces.OnCallbackListener;
+import com.luck.picture.lib.interfaces.OnCameraInterceptListener;
+import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener;
+import com.luck.picture.lib.interfaces.OnPermissionDeniedListener;
+import com.luck.picture.lib.interfaces.OnPermissionDescriptionListener;
+import com.luck.picture.lib.interfaces.OnSelectLimitTipsListener;
+import com.luck.picture.lib.permissions.PermissionConfig;
+import com.luck.picture.lib.permissions.PermissionUtil;
+import com.luck.picture.lib.style.SelectMainStyle;
+import com.luck.picture.lib.utils.DateUtils;
+import com.luck.picture.lib.utils.DensityUtil;
+import com.luck.picture.lib.utils.SandboxTransformUtils;
+import com.luck.picture.lib.utils.ToastUtils;
+import com.luck.picture.lib.widget.MediumBoldTextView;
+import com.yalantis.ucrop.UCrop;
+import com.yalantis.ucrop.UCropImageEngine;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import top.zibin.luban.CompressionPredicate;
+import top.zibin.luban.Luban;
+import top.zibin.luban.OnNewCompressListener;
+import top.zibin.luban.OnRenameListener;
+
+import com.ddddd.one.R;
+
+public class PictureSelectlucksiege {
+
+ private final static String TAG_EXPLAIN_VIEW = "TAG_EXPLAIN_VIEW";
+
+ /**
+ * 自定义压缩
+ */
+ public static class ImageFileCompressEngine implements CompressFileEngine {
+
+ @Override
+ public void onStartCompress(Context context, ArrayList source, OnKeyValueResultCallbackListener call) {
+ Luban.with(context).load(source).ignoreBy(100).setRenameListener(new OnRenameListener() {
+ @Override
+ public String rename(String filePath) {
+ int indexOf = filePath.lastIndexOf(".");
+ String postfix = indexOf != -1 ? filePath.substring(indexOf) : ".jpg";
+ String path_ = DateUtils.getCreateFileName("CMP_") + postfix;
+ Log.i("onResult", "rename: " + path_);
+ return path_;
+ }
+ }).filter(new CompressionPredicate() {
+ @Override
+ public boolean apply(String path) {
+ if (PictureMimeType.isUrlHasImage(path) && !PictureMimeType.isHasHttp(path)) {
+ return true;
+ }
+ return !PictureMimeType.isUrlHasGif(path);
+ }
+ }).setCompressListener(new OnNewCompressListener() {
+ @Override
+ public void onStart() {
+
+ }
+
+ @Override
+ public void onSuccess(String source, File compressFile) {
+ if (call != null) {
+ Log.i("onResult", "onSuccess: xxx ");
+ call.onCallback(source, compressFile.getAbsolutePath());
+ }
+ }
+
+ @Override
+ public void onError(String source, Throwable e) {
+ if (call != null) {
+ Log.i("onResult", "onError: xxx ");
+ call.onCallback(source, null);
+ }
+ }
+ }).launch();
+
+ }
+ }
+
+ /**
+ * 自定义裁剪
+ */
+ public static class ImageFileCropEngine implements CropFileEngine {
+ @Override
+ public void onStartCrop(Fragment fragment, Uri srcUri, Uri destinationUri, ArrayList dataSource, int requestCode) {
+ UCrop.Options options = PictureSelectlucksiege.buildOptions();
+ UCrop uCrop = UCrop.of(srcUri, destinationUri, dataSource);
+ uCrop.withOptions(options);
+ uCrop.setImageEngine(new UCropImageEngine() {
+ @Override
+ public void loadImage(Context context, String url, ImageView imageView) {
+ if (!ImageLoaderUtils.assertValidRequest(context)) {
+ return;
+ }
+ Glide.with(context).load(url).override(240, 240).into(imageView);
+ }
+
+ @Override
+ public void loadImage(Context context, Uri url, int maxWidth, int maxHeight, OnCallbackListener call) {
+ Glide.with(context).asBitmap().load(url).override(maxWidth, maxHeight).into(new CustomTarget() {
+ @Override
+ public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition super Bitmap> transition) {
+ if (call != null) {
+ call.onCall(resource);
+ }
+ }
+
+ @Override
+ public void onLoadCleared(@Nullable Drawable placeholder) {
+ if (call != null) {
+ call.onCall(null);
+ }
+ }
+ });
+ }
+ });
+ uCrop.start(fragment.requireActivity(), fragment, requestCode);
+ }
+ }
+
+ /**
+ * 拦截自定义提示
+ */
+ public static class MeOnSelectLimitTipsListener implements OnSelectLimitTipsListener {
+
+ @Override
+ public boolean onSelectLimitTips(Context context, @Nullable LocalMedia media, SelectorConfig config, int limitType) {
+ if (limitType == SelectLimitType.SELECT_MIN_SELECT_LIMIT) {
+ ToastUtils.showToast(context, "图片最少不能低于" + config.minSelectNum + "张");
+ return true;
+ } else if (limitType == SelectLimitType.SELECT_MIN_VIDEO_SELECT_LIMIT) {
+ ToastUtils.showToast(context, "视频最少不能低于" + config.minVideoSelectNum + "个");
+ return true;
+ } else if (limitType == SelectLimitType.SELECT_MIN_AUDIO_SELECT_LIMIT) {
+ ToastUtils.showToast(context, "音频最少不能低于" + config.minAudioSelectNum + "个");
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * 添加权限说明
+ */
+ public static class MeOnPermissionDescriptionListener implements OnPermissionDescriptionListener {
+
+ @Override
+ public void onPermissionDescription(Fragment fragment, String[] permissionArray) {
+ View rootView = fragment.requireView();
+ if (rootView instanceof ViewGroup) {
+ addPermissionDescription(false, (ViewGroup) rootView, permissionArray);
+ }
+ }
+
+ @Override
+ public void onDismiss(Fragment fragment) {
+ removePermissionDescription((ViewGroup) fragment.requireView());
+ }
+ }
+
+ /**
+ * 权限拒绝后回调
+ */
+ public static class MeOnPermissionDeniedListener implements OnPermissionDeniedListener {
+
+ @Override
+ public void onDenied(Fragment fragment, String[] permissionArray,
+ int requestCode, OnCallbackListener call) {
+ String tips;
+ if (TextUtils.equals(permissionArray[0], PermissionConfig.CAMERA[0])) {
+ tips = "Kamera erişimi yok\nKamera işlevinin kullanılamamasıyla sonuçlanacaktır.";// "缺少相机权限\n可能会导致不能使用摄像头功能";
+ } else if (TextUtils.equals(permissionArray[0], Manifest.permission.RECORD_AUDIO)) {
+ tips = "Ses kayıt erİşimi yok\nCihazınızdaki ses medya içeriği ve dosyalara erişin";// "缺少录音权限\n访问您设备上的音频、媒体内容和文件";
+ } else {
+ tips = "Depolama erişmi yok\nCihazınızdaki fotoğraf ortamı içeriğine ve dosyalara erişin";//"缺少存储权限\n访问您设备上的照片、媒体内容和文件";
+ }
+ RemindDialog dialog = RemindDialog.buildDialog(fragment.getContext(), tips);
+ dialog.setButtonText("Ayarlara git");//去设置
+ dialog.setButtonTextColor(0xFF7D7DFF);
+ dialog.setContentTextColor(0xFF333333);
+ dialog.setOnDialogClickListener(new RemindDialog.OnDialogClickListener() {
+ @Override
+ public void onClick(View view) {
+ PermissionUtil.goIntentSetting(fragment, requestCode);
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+ }
+
+ /**
+ * 自定义沙盒文件处理
+ */
+ public static class MeSandboxFileEngine implements UriToFileTransformEngine {
+
+ @Override
+ public void onUriToFileAsyncTransform(Context context, String srcPath, String mineType, OnKeyValueResultCallbackListener call) {
+ if (call != null) {
+ call.onCallback(srcPath, SandboxTransformUtils.copyPathToSandbox(context, srcPath, mineType));
+ }
+ }
+ }
+
+ /**
+ * 自定义拍照
+ */
+ public static class MeOnCameraInterceptListener implements OnCameraInterceptListener {
+ @Override
+ public void openCamera(Fragment fragment, int cameraMode, int requestCode) {
+ SimpleCameraX camera = SimpleCameraX.of();
+ camera.isAutoRotation(true);//是否自动纠偏
+ camera.setCameraMode(cameraMode);//相机模式
+ camera.setVideoFrameRate(25);
+ //camera.setVideoBitRate(3 * 1024 * 1024);
+ //camera.isDisplayRecordChangeTime(true);
+ //camera.isManualFocusCameraPreview(cb_camera_focus.isChecked());
+ camera.isZoomCameraPreview(true);//是否可缩放相机
+ camera.setOutputPathDir(getSandboxCameraOutputPath());
+ //camera.setPermissionDeniedListener(getSimpleXPermissionDeniedListener());
+ //camera.setPermissionDescriptionListener(getSimpleXPermissionDescriptionListener());
+ camera.setImageEngine(new CameraImageEngine() {
+ @Override
+ public void loadImage(Context context, String url, ImageView imageView) {
+ Glide.with(context).load(url).into(imageView);
+ }
+ });
+ camera.start(fragment.requireActivity(), fragment, requestCode);
+ }
+ }
+
+ /**
+ * 添加权限说明
+ *
+ * @param viewGroup
+ * @param permissionArray
+ */
+ private static void addPermissionDescription(boolean isHasSimpleXCamera, ViewGroup viewGroup, String[] permissionArray) {
+ int dp10 = DensityUtil.dip2px(viewGroup.getContext(), 10);
+ int dp15 = DensityUtil.dip2px(viewGroup.getContext(), 15);
+ MediumBoldTextView view = new MediumBoldTextView(viewGroup.getContext());
+ view.setTag(TAG_EXPLAIN_VIEW);
+ view.setTextSize(14);
+ view.setTextColor(Color.parseColor("#333333"));
+ view.setPadding(dp10, dp15, dp10, dp15);
+
+ String title;
+ String explain;
+
+ if (TextUtils.equals(permissionArray[0], PermissionConfig.CAMERA[0])) {
+ title = "Kamera izinlerini kullanma açıklaması";//"相机权限使用说明";
+ explain = "Fotoğraf çekmek/Video kaydetmek için";//"相机权限使用说明\n用户app用于拍照/录视频";
+ } else if (TextUtils.equals(permissionArray[0], Manifest.permission.RECORD_AUDIO)) {
+ if (isHasSimpleXCamera) {
+ title = "Mikrofon izinlerini kullanma açıklaması";//""麦克风权限使用说明";
+ explain = "Video kaydederken ses toplama için";//""麦克风权限使用说明\n用户app用于录视频时采集声音";
+ } else {
+ title = "Ses kayıt izinlerini kullanma açıklaması";//"录音权限使用说明";
+ explain = "Ses toplama için";//"录音权限使用说明\n用户app用于采集声音";
+ }
+ } else {
+ title = "Depolama izinlerini kullanma açıklaması";// "存储权限使用说明";
+ explain = "yazma/indirme/kaydetme/okuma/değiştirme/video/dosya ve bilgiler ve resimleri silmek için kullanılır";//"存储权限使用说明\n用户app写入/下载/保存/读取/修改/删除图片、视频、文件等信息";
+ }
+ int startIndex = 0;
+ int endOf = startIndex + title.length();
+ SpannableStringBuilder builder = new SpannableStringBuilder(explain);
+ builder.setSpan(new AbsoluteSizeSpan(DensityUtil.dip2px(viewGroup.getContext(), 16)), startIndex, endOf, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ builder.setSpan(new ForegroundColorSpan(0xFF333333), startIndex, endOf, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ view.setText(builder);
+ view.setBackground(ContextCompat.getDrawable(viewGroup.getContext(), R.drawable.ps_permission));
+
+ if (isHasSimpleXCamera) {
+ RelativeLayout.LayoutParams layoutParams =
+ new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+ layoutParams.topMargin = DensityUtil.getStatusBarHeight(viewGroup.getContext());
+ layoutParams.leftMargin = dp10;
+ layoutParams.rightMargin = dp10;
+ viewGroup.addView(view, layoutParams);
+ } else {
+ ConstraintLayout.LayoutParams layoutParams =
+ new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
+ layoutParams.topToBottom = R.id.title_bar;
+ layoutParams.leftToLeft = ConstraintSet.PARENT_ID;
+ layoutParams.leftMargin = dp10;
+ layoutParams.rightMargin = dp10;
+ viewGroup.addView(view, layoutParams);
+ }
+ }
+
+ /**
+ * 移除权限说明
+ *
+ * @param viewGroup
+ */
+ private static void removePermissionDescription(ViewGroup viewGroup) {
+ View tagExplainView = viewGroup.findViewWithTag(TAG_EXPLAIN_VIEW);
+ viewGroup.removeView(tagExplainView);
+ }
+
+
+ /**
+ * 配制UCrop,可根据需求自我扩展
+ *
+ * @return
+ */
+ private static UCrop.Options buildOptions() {
+ UCrop.Options options = new UCrop.Options();
+ options.setHideBottomControls(true);//设置为true以隐藏底部控件(默认显示)
+ options.setFreeStyleCropEnabled(true);//允许用户调整裁剪边界的大小
+ options.setShowCropFrame(true);//图像顶部看到裁剪框矩形
+ options.setShowCropGrid(true);//如果希望在图像顶部看到裁剪网格/指导线,请设置为true
+ options.setCircleDimmedLayer(true);//如果希望暗显层内部有一个圆圈,请将其设置为true
+ options.withAspectRatio(240, 240);//设置裁剪边界的纵横比。用户将看不到带有其他比例选项的菜单。
+// options.setCropOutputPathDir(getSandboxPath());
+ options.isCropDragSmoothToCenter(true);//自动居中裁剪和拖动
+// options.setSkipCropMimeType(getNotSupportCrop());//Skip crop mimeType
+// options.isForbidCropGifWebp(cb_not_gif.isChecked());//你需要支持剪切动态图形吗gif或webp
+// options.isForbidSkipMultipleCrop(true);//切割多个图纸时禁止跳过
+ options.setMaxScaleMultiplier(100);//该方法设置用于从最小图像比例计算最大图像比例的乘数
+// if (selectorStyle != null && selectorStyle.getSelectMainStyle().getStatusBarColor() != 0) {
+// SelectMainStyle mainStyle = selectorStyle.getSelectMainStyle();
+// boolean isDarkStatusBarBlack = mainStyle.isDarkStatusBarBlack();
+// int statusBarColor = mainStyle.getStatusBarColor();
+// options.isDarkStatusBarBlack(isDarkStatusBarBlack);
+// if (StyleUtils.checkStyleValidity(statusBarColor)) {
+// options.setStatusBarColor(statusBarColor);
+// options.setToolbarColor(statusBarColor);
+// } else {
+// options.setStatusBarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey));
+// options.setToolbarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey));
+// }
+// TitleBarStyle titleBarStyle = selectorStyle.getTitleBarStyle();
+// if (StyleUtils.checkStyleValidity(titleBarStyle.getTitleTextColor())) {
+// options.setToolbarWidgetColor(titleBarStyle.getTitleTextColor());
+// } else {
+// options.setToolbarWidgetColor(ContextCompat.getColor(getContext(), R.color.ps_color_white));
+// }
+// } else {
+// options.setStatusBarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey));
+// options.setToolbarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey));
+// options.setToolbarWidgetColor(ContextCompat.getColor(getContext(), R.color.ps_color_white));
+// }
+ options.setStatusBarColor(ContextCompat.getColor(AppActivity.nAppActivity, R.color.ps_color_grey));
+ options.setToolbarColor(ContextCompat.getColor(AppActivity.nAppActivity, R.color.ps_color_grey));
+ options.setToolbarWidgetColor(ContextCompat.getColor(AppActivity.nAppActivity, R.color.ps_color_white));
+
+ return options;
+ }
+
+ /**
+ * 创建相机自定义输出目录
+ *
+ * @return
+ */
+ private static String getSandboxCameraOutputPath() {
+ File externalFilesDir = AppActivity.nAppActivity.getExternalFilesDir("");
+ File customFile = new File(externalFilesDir.getAbsolutePath(), "Sandbox");
+ if (!customFile.exists()) {
+ customFile.mkdirs();
+ }
+ return customFile.getAbsolutePath() + File.separator;
+ }
+}
diff --git a/android/app/src/com/cocos/game/ShakeDetector.java b/android/app/src/com/cocos/game/ShakeDetector.java
new file mode 100644
index 0000000..7c9136a
--- /dev/null
+++ b/android/app/src/com/cocos/game/ShakeDetector.java
@@ -0,0 +1,153 @@
+package com.cocos.game;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+/**
+ * 用于检测手机摇晃
+ *
+ * @author 郑智仁
+ * @see Blog
+ */
+public class ShakeDetector implements SensorEventListener {
+ /**
+ * 检测的时间间隔
+ */
+ static final int UPDATE_INTERVAL = 100;
+ /**
+ * 上一次检测的时间
+ */
+ long mLastUpdateTime;
+ /**
+ * 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。
+ */
+ float mLastX, mLastY, mLastZ;
+ float[] poses = new float[3];
+ Context mContext;
+ SensorManager mSensorManager;
+ ArrayList mListeners;
+ /**
+ * 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。
+ */
+ public int shakeThreshold = 300;
+
+ public ShakeDetector(Context context) {
+ mContext = context;
+ mSensorManager = (SensorManager) context
+ .getSystemService(Context.SENSOR_SERVICE);
+ mListeners = new ArrayList();
+
+ }
+
+ public float[] getposes() {
+ return poses;
+ }
+
+ ;
+
+ /**
+ * 当摇晃事件发生时,接收通知
+ */
+ public interface OnShakeListener {
+ /**
+ * 当手机摇晃时被调用
+ */
+ void onShake();
+ }
+
+ /**
+ * 注册OnShakeListener,当摇晃时接收通知
+ *
+ * @param listener
+ */
+ public void registerOnShakeListener(OnShakeListener listener) {
+ if (mListeners.contains(listener))
+ return;
+ mListeners.add(listener);
+ }
+
+ /**
+ * 移除已经注册的OnShakeListener
+ *
+ * @param listener
+ */
+ public void unregisterOnShakeListener(OnShakeListener listener) {
+ mListeners.remove(listener);
+ }
+
+ /**
+ * 启动摇晃检测
+ */
+ public void start() {
+ if (mSensorManager == null) {
+ throw new UnsupportedOperationException();
+ }
+ Sensor sensor = mSensorManager
+ .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (sensor == null) {
+ throw new UnsupportedOperationException();
+ }
+ boolean success = mSensorManager.registerListener(this, sensor,
+ SensorManager.SENSOR_DELAY_GAME);
+ if (!success) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * 停止摇晃检测
+ */
+ public void stop() {
+ if (mSensorManager != null)
+ mSensorManager.unregisterListener(this);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ long currentTime = System.currentTimeMillis();
+ long diffTime = currentTime - mLastUpdateTime;
+ if (diffTime < UPDATE_INTERVAL)
+ return;
+ mLastUpdateTime = currentTime;
+ float x = event.values[0];
+ float y = event.values[1];
+ float z = event.values[2];
+ float deltaX = x - mLastX;
+ float deltaY = y - mLastY;
+ float deltaZ = z - mLastZ;
+ mLastX = x;
+ mLastY = y;
+ mLastZ = z;
+ float delta = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
+ * deltaZ);
+
+ delta = delta * 10000 / diffTime;
+// Log.d("delta", "解析delta,: " + delta + "diffTime :" + diffTime);
+ if (delta > shakeThreshold) { // 当加速度的差值大于指定的阈值,认为这是一个摇晃
+ this.notifyListeners();
+ }
+
+ poses[0] = x;
+ poses[1] = y;
+ poses[2] = z;
+ }
+
+ /**
+ * 当摇晃事件发生时,通知所有的listener
+ */
+ private void notifyListeners() {
+ for (OnShakeListener listener : mListeners) {
+ listener.onShake();
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/com/cocos/game/ZegoUtil.java b/android/app/src/com/cocos/game/ZegoUtil.java
new file mode 100644
index 0000000..de57479
--- /dev/null
+++ b/android/app/src/com/cocos/game/ZegoUtil.java
@@ -0,0 +1,469 @@
+package com.cocos.game;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Message;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.cocos.lib.JsbBridgeWrapper;
+import com.ddddd.one.R;
+
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import im.zego.zegoexpress.ZegoExpressEngine;
+import im.zego.zegoexpress.callback.IZegoEventHandler;
+import im.zego.zegoexpress.constants.ZegoPlayerState;
+import im.zego.zegoexpress.constants.ZegoPublisherState;
+import im.zego.zegoexpress.constants.ZegoRoomStateChangedReason;
+import im.zego.zegoexpress.constants.ZegoScenario;
+import im.zego.zegoexpress.constants.ZegoUpdateType;
+import im.zego.zegoexpress.entity.ZegoEngineConfig;
+import im.zego.zegoexpress.entity.ZegoEngineProfile;
+import im.zego.zegoexpress.entity.ZegoStream;
+import im.zego.zegoexpress.entity.ZegoUser;
+
+public class ZegoUtil {
+ private static final String TAG = "ZegoUtil";
+ private static ZegoUtil sInstance = null;
+
+ public static ZegoUtil getInstance() {
+ if (sInstance == null) {
+ sInstance = new ZegoUtil();
+ }
+ return sInstance;
+ }
+
+ // JAVA
+ private JsbBridgeWrapper jbw = null;
+
+ public JsbBridgeWrapper GetJsbBridgeWrapper() {
+ if (jbw == null) {
+ jbw = JsbBridgeWrapper.getInstance();
+ }
+ return jbw;
+ }
+
+ private static Context mContext;
+ private static AppActivity mActivity;
+
+ /**
+ * 初始化信息
+ *
+ * @param activity
+ */
+ private static void InitInfo(AppActivity activity, Context _context) {
+ if (mActivity == null)
+ mActivity = activity;
+ if (mContext == null)
+ mContext = _context;
+ }
+
+ /**
+ * 定义 SDK 引擎对象
+ */
+ private ZegoExpressEngine zegoExpressEngine;
+ /**
+ * 加入频道json字符串
+ */
+ public static String ZegoJoinJsonStr = "";
+ private static List ZegoStreamList = new ArrayList<>();
+ private static List CloseZegoStreamList = new ArrayList<>();
+ private static boolean isClosePublishingStream = true;
+
+ public void zegoDestroyEngine() {
+ if (zegoExpressEngine != null) {
+ ZegoJoinJsonStr = "";
+ ZegoStreamList.clear();
+ CloseZegoStreamList.clear();
+ isClosePublishingStream = true;
+ // 退出全部房间
+ zegoExpressEngine.logoutRoom();
+ /** 销毁 SDK */
+ zegoExpressEngine.destroyEngine(null);
+ zegoExpressEngine = null;
+ }
+ }
+
+ /**
+ * 调用 zego SDK 的方法初始化。
+ */
+ public void zegoInitializeEngine(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+
+ try {
+ String zego_id = mActivity.getResources().getString(R.string.zego_appID);
+ Log.d(TAG, "zegoInitializeEngine: => " + zego_id);
+
+ ZegoEngineConfig engineConfig = new ZegoEngineConfig();
+ engineConfig.advancedConfig.put("audio_device_mode", "1");
+ ZegoExpressEngine.setEngineConfig(engineConfig);
+
+ ZegoEngineProfile profile = new ZegoEngineProfile();
+ /** 请通过官网注册获取,格式为 123456789L */
+ profile.appID = Long.parseLong(zego_id.replace("zego_", ""));//mActivity.getResources().getInteger(R.integer.zego_appID);
+ /** 64个字符,请通过官网注册获取,格式为"0123456789012345678901234567890123456789012345678901234567890123" */
+ profile.appSign = mActivity.getString(R.string.zego_appSign).replace("zego_", "");
+ /** 通用场景接入 */
+ profile.scenario = ZegoScenario.STANDARD_CHATROOM;//;
+ /** 设置app的application 对象 */
+ profile.application = mActivity.getApplication();
+ /** 创建引擎 */
+ zegoExpressEngine = ZegoExpressEngine.createEngine(profile, zegoEventHandler);
+
+ zegoLogin(nAppActivity, _context);
+ zegoLoginOut(nAppActivity, _context);
+ zegoStartPublishingStream(nAppActivity, _context);
+ zegoStopPublishingStream(nAppActivity, _context);
+ zegoMuteAllPlayStreamAudio(nAppActivity, _context);
+ zegoStartPlayingStream(nAppActivity, _context);
+ zegoStopPlayingStream(nAppActivity, _context);
+ } catch (Exception e) {
+ Log.d(TAG, "zegoInitializeEngine: error=> " + Log.getStackTraceString(e));
+ }
+ }
+
+ /**
+ * 加入频道:供LUA调用
+ */
+ public void zegoLogin(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_Login, arg -> {
+ try {
+ Log.d(TAG, "zegoLogin: " + arg);
+ ZegoJoinJsonStr = arg;
+
+ Message msg = new Message();
+ msg.what = nAppActivity.HANDLER_ZEGOLOGIN;
+ msg.obj = arg;
+ nAppActivity.handler.sendMessage(msg);
+
+ } catch (Exception exception) {
+ Log.d(TAG, "zegoLogin:=>error " + exception.toString());
+ exception.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * 加入频道:供LUA调用
+ */
+ public void zegoLoginFun(AppActivity nAppActivity, Context _context, String param) {
+ InitInfo(nAppActivity, _context);
+ try {
+ Log.d(TAG, "zegoLoginFun: " + param);
+
+ JSONObject jo = new JSONObject(param);
+ String userId = jo.getString("userId");
+ String roomId = jo.getString("roomId");
+
+ /** 创建用户 */
+ ZegoUser user = new ZegoUser(userId);
+ /** 开始登陆房间 */
+ zegoExpressEngine.loginRoom(roomId, user);
+ zegoExpressEngine.startPublishingStream(userId);
+ zegoExpressEngine.startSoundLevelMonitor(200);//启动声浪监控
+ isClosePublishingStream = false;
+
+ String reStr = "0";
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_Login, reStr);
+ } catch (Exception exception) {
+ Log.d(TAG, "zegoLoginFun:=>error " + exception.toString());
+ exception.printStackTrace();
+ }
+ }
+
+ /**
+ * 离开频道:供LUA调用
+ */
+ public void zegoLoginOut(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_LoginOut, arg -> {
+ try {
+ CloseZegoStreamList.clear();
+ zegoExpressEngine.logoutRoom();
+ } catch (Exception exception) {
+ Log.d(TAG, "zegoLoginOut: =>error " + exception.toString());
+ }
+ });
+ }
+
+ /**
+ * 取消或恢复发布本地音频流:供LUA调用 - 推流
+ */
+ public void zegoStartPublishingStream(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_StartPublish, strParam -> {
+ try {
+ Log.i(TAG, "zegoStartPublishingStream:=>strParam " + strParam);
+
+ JSONObject jo = new JSONObject(strParam);
+ String streamId = jo.getString("streamId");
+ isClosePublishingStream = false;
+ zegoExpressEngine.startPublishingStream(streamId);
+
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_StartPublish, "0|false");
+ } catch (Exception e) {
+ Log.i(TAG, "zegoStartPublishingStream: =>error " + e.toString());
+ }
+ });
+ }
+
+ /**
+ * 取消或恢复发布本地音频流:供LUA调用 - 停推流
+ */
+ public void zegoStopPublishingStream(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_StopPublish, strParam -> {
+ try {
+ Log.i(TAG, "zegoStopPublishingStream:=>strParam " + strParam);
+ isClosePublishingStream = true;
+ zegoExpressEngine.stopPublishingStream();
+
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_StopPublish, "0|true");
+ } catch (Exception e) {
+ Log.i(TAG, "zegoStopPublishingStream: =>error " + e.toString());
+ }
+ });
+ }
+
+ /**
+ * 取消或恢复订阅所有远端用户的音频流:供LUA调用
+ */
+ public void zegoMuteAllPlayStreamAudio(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_AllPlay, muteBean -> {
+ try {
+ Log.i(TAG, "zegoMuteAllPlayStreamAudio:=>strParam " + muteBean);
+
+ JSONObject jo = new JSONObject(muteBean);
+ boolean muted = jo.getBoolean("muted");
+
+ zegoExpressEngine.muteAllPlayStreamAudio(muted);
+
+ } catch (Exception e) {
+ Log.i(TAG, "zegoMuteAllPlayStreamAudio: =>error " + e.toString());
+ }
+ });
+ }
+
+ /**
+ * 取消或恢复订阅指定远端用户的音频流:供LUA调用 - 拉流
+ */
+ public void zegoStartPlayingStream(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_StartPlay, muteBean -> {
+ try {
+ Log.i(TAG, "zegoStartPlayingStream:=>strParam " + muteBean);
+
+ JSONObject jo = new JSONObject(muteBean);
+ String streamId = jo.getString("streamId");
+
+ if (CloseZegoStreamList.contains(streamId))
+ CloseZegoStreamList.remove(streamId);
+
+ zegoExpressEngine.startPlayingStream(streamId);
+
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_StartPlay, "0|" + streamId + "|false");
+ } catch (Exception e) {
+ Log.i(TAG, "zegoStartPlayingStream: =>error " + e.toString());
+ }
+ });
+ }
+
+ /**
+ * 取消或恢复订阅指定远端用户的音频流:供LUA调用 - 停拉流
+ */
+ public void zegoStopPlayingStream(AppActivity nAppActivity, Context _context) {
+ InitInfo(nAppActivity, _context);
+ GetJsbBridgeWrapper().addScriptEventListener(EventNameUtil.Zg_StopPlay, muteBean -> {
+ try {
+ Log.i(TAG, "zegoStartPlayingStream:=>strParam " + muteBean);
+
+ JSONObject jo = new JSONObject(muteBean);
+ String streamId = jo.getString("streamId");
+ if (!CloseZegoStreamList.contains(streamId))
+ CloseZegoStreamList.add(streamId);
+
+ zegoExpressEngine.stopPlayingStream(streamId);
+
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_StopPlay, "0|" + streamId + "|true");
+ } catch (Exception e) {
+ Log.i(TAG, "zegoStartPlayingStream: =>error " + e.toString());
+ }
+ });
+ }
+
+ /**
+ * 判断是否有语音权限
+ *
+ * @return
+ */
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ public boolean checkAudioSelfPermission() {
+ return mActivity.getApplicationContext().checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private final IZegoEventHandler zegoEventHandler = new IZegoEventHandler() {
+ /** 房间状态更新回调 */
+ @Override
+ public void onRoomStateChanged(String roomID, ZegoRoomStateChangedReason reason, int errorCode, JSONObject extendedData) {
+ super.onRoomStateChanged(roomID, reason, errorCode, extendedData);
+ Log.i(TAG, "onRoomStatZg_LogineUpdate: 🚩 🚪 Login room reason " + reason + " roomID:" + roomID + " errorCode:" + errorCode);
+ if (reason == ZegoRoomStateChangedReason.LOGINING) {
+ // 登录中
+ Log.i(TAG, "onRoomStateChanged: 登录中");
+ } else if (reason == ZegoRoomStateChangedReason.LOGINED) {
+ // 登录成功
+ //只有当房间状态是登录成功或重连成功时,推流(startPublishingStream)、拉流(startPlayingStream)才能正常收发音视频
+ //将自己的音视频流推送到 ZEGO 音视频云
+ Log.i(TAG, "onRoomStateChanged: 登录成功");
+ } else if (reason == ZegoRoomStateChangedReason.LOGIN_FAILED) {
+ // 登录失败
+ Log.i(TAG, "onRoomStateChanged: 登录失败");
+ } else if (reason == ZegoRoomStateChangedReason.RECONNECTING) {
+ // 重连中
+ Log.i(TAG, "onRoomStateChanged: 重连中");
+ } else if (reason == ZegoRoomStateChangedReason.RECONNECTED) {
+ // 重连成功
+ Log.i(TAG, "onRoomStateChanged: 重连成功");
+ } else if (reason == ZegoRoomStateChangedReason.RECONNECT_FAILED) {
+ // 重连失败
+ Log.i(TAG, "onRoomStateChanged: 重连失败");
+ } else if (reason == ZegoRoomStateChangedReason.KICK_OUT) {
+ // 被踢出房间
+ Log.i(TAG, "onRoomStateChanged: 被踢出房间");
+ } else if (reason == ZegoRoomStateChangedReason.LOGOUT) {
+ // 登出成功
+ Log.i(TAG, "onRoomStateChanged: 登出成功");
+ } else if (reason == ZegoRoomStateChangedReason.LOGOUT_FAILED) {
+ // 登出失败
+ Log.i(TAG, "onRoomStateChanged: 登出失败");
+ }
+ }
+// /** 房间状态更新回调 */
+// @Override
+// public void onRoomStateUpdate(String roomID, ZegoRoomState state, int errorCode, JSONObject extendedData) {
+// /** 根据需要实现事件回调 */
+// if (state == ZegoRoomState.CONNECTED && errorCode == 0) {
+// Log.i(TAG, "onRoomStatZg_LogineUpdate: 🚩 🚪 Login room success");
+// }
+// if (errorCode != 0) {
+// Log.i(TAG, "onRoomStateUpdate: 🚩 ❌ 🚪 Login room fail, errorCode: " + errorCode);
+// }
+// }
+
+ /** 用户状态更新 */
+ @Override
+ public void onRoomUserUpdate(String roomID, ZegoUpdateType updateType, ArrayList userList) {
+ super.onRoomUserUpdate(roomID, updateType, userList);
+ /** 根据需要实现事件回调 */
+ }
+
+ /**
+ * 流状态更新
+ */
+ @Override
+ public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, ArrayList streamList, JSONObject extendedData) {
+ /** 根据需要实现事件回调 */
+ super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);
+ // Log.i(Zego_TAG, "🚩 🌊 onRoomStreamUpdate: roomID" + roomID + ", updateType:" + updateType.value() + ", streamList: " + streamList);
+
+ // Add the rendered view dynamically after pulling the stream here
+ if (updateType == ZegoUpdateType.ADD) {
+ for (ZegoStream zegoStream : streamList) {
+ if (!ZegoStreamList.contains(zegoStream)) {
+ ZegoStreamList.add(zegoStream);
+ }
+
+ if (!CloseZegoStreamList.contains(zegoStream.streamID))
+ ZegoExpressEngine.getEngine().startPlayingStream(zegoStream.streamID);
+ }
+ } else if (updateType == ZegoUpdateType.DELETE) {
+ for (ZegoStream zegoStream : streamList) {
+ if (ZegoStreamList.contains(zegoStream)) {
+ ZegoStreamList.remove(zegoStream);
+ }
+
+ ZegoExpressEngine.getEngine().stopPlayingStream(zegoStream.streamID);
+ }
+ }
+ }
+
+ /** 推流状态更新回调*/
+ @Override
+ public void onPublisherStateUpdate(String streamID, ZegoPublisherState state, int errorCode, JSONObject extendedData) {
+ // Log.i(Zego_TAG, "onPublisherStateUpdate streamID:"+streamID+" state:"+state);
+ if (state == ZegoPublisherState.PUBLISHING && errorCode == 0) {
+ Log.i(TAG, "onPublisherStateUpdate:🚩 📤 Publishing stream success");
+ }
+ if (errorCode != 0) {
+ Log.i(TAG, "onPublisherStateUpdate: 🚩 ❌ 📤 Publishing stream fail, errorCode: " + errorCode);
+ }
+ }
+
+ /** 拉流状态更新回调*/
+ @Override
+ public void onPlayerStateUpdate(String streamID, ZegoPlayerState state, int errorCode, JSONObject extendedData) {
+ // Log.i(Zego_TAG, "onPlayerStateUpdate streamID:"+streamID+" state:"+state);
+ if (state == ZegoPlayerState.PLAYING && errorCode == 0) {
+ Log.i(TAG, "onPlayerStateUpdate: 🚩 📥 Playing stream success");
+ }
+ if (errorCode != 0) {
+ Log.i(TAG, "onPlayerStateUpdate: 🚩 ❌ 📥 Playing stream fail, errorCode: " + errorCode);
+ }
+ }
+
+ /** 接收远端拉流音频声浪回调 */
+ @Override
+ public void onRemoteSoundLevelUpdate(HashMap soundLevels) {
+ super.onRemoteSoundLevelUpdate(soundLevels);
+// Log.i(Zego_TAG, "onRemoteSoundLevelUpdate:"+ soundLevels.size());
+ for (HashMap.Entry entry : soundLevels.entrySet()) {
+ String streamid = entry.getKey();
+ Float value = entry.getValue();
+ if (value > 10 && !streamid.equals("")) {
+ String speakers_str = streamid + "|" + value;
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_AudioVolume, speakers_str);
+ }
+ }
+ }
+
+ /** 本地采集音频声浪回调 */
+ @Override
+ public void onCapturedSoundLevelUpdate(float soundLevel) {
+ super.onCapturedSoundLevelUpdate(soundLevel);
+ // Log.v(TAG, "onCapturedSoundLevelUpdate:" + soundLevel);
+ if (!isClosePublishingStream && soundLevel > 10) {
+ String speakers_str = "0|" + soundLevel;
+ EventToScriptUtil.getInstance().dispatchEventToScript(EventNameUtil.Zg_AudioVolume, speakers_str);
+ }
+ }
+
+// @Override
+// public void onCapturedSoundLevelInfoUpdate(ZegoSoundLevelInfo soundLevelInfo) {
+// super.onCapturedSoundLevelInfoUpdate(soundLevelInfo);
+// Log.v("ZegoAudioTalk", "onCapturedSoundLevelUpdate:" + soundLevelInfo.soundLevel);
+//// if(soundLevelInfo.soundLevel > 0 && soundLevelInfo.vad == 1){
+////
+//// }
+// final String speakers_str = "0|" + soundLevelInfo.soundLevel;
+// nAppActivity.runOnGLThread(new Runnable() {
+// @Override
+// public void run() {
+// // 用户的音量 > 0 回调到lua 对应的玩家显示正在说话的状态
+// Cocos2dxLuaJavaBridge.callLuaGlobalFunctionWithString(
+// "Zego_OnAudioVolume", speakers_str + "");
+// }
+// });
+// }
+ };
+}
diff --git a/android/build.gradle b/android/build.gradle
index 183885e..a6985ee 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -17,6 +17,7 @@ buildscript {
allprojects {
repositories {
+ maven { url 'https://storage.zego.im/maven' }
google()
mavenCentral()
// jcenter() // keeped as anchor, will be removed soon
diff --git a/android/res/drawable/ps_image_placeholder.xml b/android/res/drawable/ps_image_placeholder.xml
new file mode 100644
index 0000000..bdf2627
--- /dev/null
+++ b/android/res/drawable/ps_image_placeholder.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/android/res/drawable/ps_permission.png b/android/res/drawable/ps_permission.png
new file mode 100644
index 0000000..d3ef347
Binary files /dev/null and b/android/res/drawable/ps_permission.png differ
diff --git a/android/res/drawable/splash.png b/android/res/drawable/splash.png
new file mode 100644
index 0000000..0977c40
Binary files /dev/null and b/android/res/drawable/splash.png differ
diff --git a/android/res/mipmap-hdpi/ic_launcher.png b/android/res/mipmap-hdpi/ic_launcher.png
index 888c0d5..b6e92ec 100644
Binary files a/android/res/mipmap-hdpi/ic_launcher.png and b/android/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-mdpi/ic_launcher.png b/android/res/mipmap-mdpi/ic_launcher.png
index d5e3c77..fa955dc 100644
Binary files a/android/res/mipmap-mdpi/ic_launcher.png and b/android/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xhdpi/ic_launcher.png b/android/res/mipmap-xhdpi/ic_launcher.png
index 2b6f32a..a52c8be 100644
Binary files a/android/res/mipmap-xhdpi/ic_launcher.png and b/android/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xxhdpi/ic_launcher.png b/android/res/mipmap-xxhdpi/ic_launcher.png
index 2f1e5a6..1aa1112 100644
Binary files a/android/res/mipmap-xxhdpi/ic_launcher.png and b/android/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xxxhdpi/ic_launcher.png b/android/res/mipmap-xxxhdpi/ic_launcher.png
index a9ebc79..5683c85 100644
Binary files a/android/res/mipmap-xxxhdpi/ic_launcher.png and b/android/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/res/values/colors.xml b/android/res/values/colors.xml
new file mode 100644
index 0000000..3010a63
--- /dev/null
+++ b/android/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #666666
+ #FFFFFF
+
diff --git a/android/res/values/ids.xml b/android/res/values/ids.xml
new file mode 100644
index 0000000..d6948b9
--- /dev/null
+++ b/android/res/values/ids.xml
@@ -0,0 +1,7 @@
+
+
+
+ 77777777777
+
+
+
\ No newline at end of file
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 8542005..4fed8d4 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -1,2 +1,18 @@
+ 101 Okey Neşeli
+
+
+
+ 77777777777-pe7pidhpuc9ohkg5t8aqip7qboire346.apps.googleusercontent.com
+
+
+ 4fbx099pwqv4
+
+ 63f5a8b9d4
+ 1.0.0
+ happyokey
+ false
+
+ zego_57566727
+ zego_e7e8723ad58492924c5c26087f735ee2f8b748cbd30acff1194ef1b37810f389
diff --git a/build.gradle b/build.gradle
index 899d584..a42ed4d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,6 +9,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.10.1'
+ classpath 'com.google.gms:google-services:4.4.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
new file mode 100644
index 0000000..2a65780
--- /dev/null
+++ b/common/CMakeLists.txt
@@ -0,0 +1,57 @@
+enable_language(C ASM)
+set(DEVELOPMENT_TEAM "" CACHE STRING "APPLE Developtment Team")
+set(RES_DIR "" CACHE STRING "Resource path")
+set(COCOS_X_PATH "" CACHE STRING "Path to engine/native/")
+
+set(TARGET_OSX_VERSION "10.14" CACHE STRING "Target MacOSX version" FORCE)
+set(TARGET_IOS_VERSION "11.0" CACHE STRING "Target iOS version" FORCE)
+
+set(CMAKE_CXX_STANDARD 17)
+option(CC_DEBUG_FORCE "Force enable CC_DEBUG in release mode" OFF)
+option(USE_SE_V8 "Use V8 JavaScript Engine" ON)
+option(USE_SE_JSVM "Use JSVM JavaScript Engine" OFF)
+option(USE_SE_JSC "Use JavaScriptCore on MacOSX/iOS" OFF)
+option(USE_V8_DEBUGGER "Compile v8 inspector ws server" ON)
+option(USE_V8_DEBUGGER_FORCE "Force enable debugger in release mode" OFF)
+option(USE_SOCKET "Enable WebSocket & SocketIO" ON)
+option(USE_AUDIO "Enable Audio" ON) #Enable AudioEngine
+option(USE_EDIT_BOX "Enable EditBox" ON)
+option(USE_VIDEO "Enable VideoPlayer Component" ON)
+option(USE_WEBVIEW "Enable WebView Component" ON)
+option(USE_MIDDLEWARE "Enable Middleware" ON)
+option(USE_DRAGONBONES "Enable Dragonbones" ON)
+option(USE_SPINE_3_8 "Enable Spine 3.8" ON)
+option(USE_SPINE_4_2 "Enable Spine 4.2" OFF)
+option(USE_WEBSOCKET_SERVER "Enable WebSocket Server" OFF)
+option(USE_JOB_SYSTEM_TASKFLOW "Use taskflow as job system backend" OFF)
+option(USE_JOB_SYSTEM_TBB "Use tbb as job system backend" OFF)
+option(USE_PHYSICS_PHYSX "Use PhysX Physics" ON)
+option(USE_OCCLUSION_QUERY "Use Occlusion Query" ON)
+option(USE_DEBUG_RENDERER "Use Debug Renderer" ON)
+option(USE_GEOMETRY_RENDERER "Use Geometry Renderer" ON)
+option(USE_WEBP "Use Webp" ON)
+
+if(NOT RES_DIR)
+ message(FATAL_ERROR "RES_DIR is not set!")
+endif()
+
+include(${RES_DIR}/proj/cfg.cmake)
+
+if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
+endif()
+
+if(NOT COCOS_X_PATH)
+ message(FATAL_ERROR "COCOS_X_PATH is not set!")
+endif()
+
+if(USE_XR OR USE_AR_MODULE)
+ include(${CMAKE_CURRENT_LIST_DIR}/xr.cmake)
+endif()
+
+include(${COCOS_X_PATH}/CMakeLists.txt)
+
+list(APPEND CC_COMMON_SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/Classes/Game.h
+ ${CMAKE_CURRENT_LIST_DIR}/Classes/Game.cpp
+)
diff --git a/common/Classes/Game.cpp b/common/Classes/Game.cpp
new file mode 100644
index 0000000..c15664c
--- /dev/null
+++ b/common/Classes/Game.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+ Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
+
+ http://www.cocos.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You
+ shall not use Cocos Creator software for developing other software or tools
+ that's used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to
+ you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+#include "Game.h"
+
+#ifndef GAME_NAME
+#define GAME_NAME "CocosGame";
+#endif
+
+#ifndef SCRIPT_XXTEAKEY
+#define SCRIPT_XXTEAKEY "";
+#endif
+
+Game::Game() = default;
+
+int Game::init() {
+ _windowInfo.title = GAME_NAME;
+ // configurate window size
+ // _windowInfo.height = 600;
+ // _windowInfo.width = 800;
+
+#if CC_DEBUG
+ _debuggerInfo.enabled = true;
+#else
+ _debuggerInfo.enabled = false;
+#endif
+ _debuggerInfo.port = 6086;
+ _debuggerInfo.address = "0.0.0.0";
+ _debuggerInfo.pauseOnStart = false;
+
+ _xxteaKey = SCRIPT_XXTEAKEY;
+
+ BaseGame::init();
+ return 0;
+}
+
+void Game::onPause() { BaseGame::onPause(); }
+
+void Game::onResume() { BaseGame::onResume(); }
+
+void Game::onClose() { BaseGame::onClose(); }
+
+CC_REGISTER_APPLICATION(Game);
diff --git a/common/Classes/Game.h b/common/Classes/Game.h
new file mode 100644
index 0000000..521615e
--- /dev/null
+++ b/common/Classes/Game.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+ Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
+
+ http://www.cocos.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated engine source code (the "Software"), a limited,
+ worldwide, royalty-free, non-assignable, revocable and non-exclusive license
+ to use Cocos Creator solely to develop games on your target platforms. You
+ shall not use Cocos Creator software for developing other software or tools
+ that's used for developing games. You are not granted to publish, distribute,
+ sublicense, and/or sell copies of Cocos Creator.
+
+ The software or tools in this License Agreement are licensed, not sold.
+ Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to
+ you.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ ****************************************************************************/
+#pragma once
+
+#include "cocos/cocos.h"
+
+/**
+ @brief The cocos2d Application.
+
+ The reason for implement as private inheritance is to hide some interface call
+ by Director.
+ */
+class Game : public cc::BaseGame {
+public:
+ Game();
+ int init() override;
+ // bool init() override;
+ void onPause() override;
+ void onResume() override;
+ void onClose() override;
+};
diff --git a/common/cocos-version.json b/common/cocos-version.json
new file mode 100644
index 0000000..6d8c4d7
--- /dev/null
+++ b/common/cocos-version.json
@@ -0,0 +1 @@
+{"version":"3.8.8","skipCheck":false}
diff --git a/common/localCfg.cmake b/common/localCfg.cmake
new file mode 100644
index 0000000..f17333e
--- /dev/null
+++ b/common/localCfg.cmake
@@ -0,0 +1,3 @@
+## Add or overwrite options from cfg.cmake.
+## This file is ignored from git.
+# set(NODE_EXECUTABLE /opt/...)
\ No newline at end of file
diff --git a/common/xr.cmake b/common/xr.cmake
new file mode 100644
index 0000000..e4d666d
--- /dev/null
+++ b/common/xr.cmake
@@ -0,0 +1,20 @@
+
+include(${COCOS_X_PATH}/cmake/predefine.cmake)
+
+if(NOT DEFINED XR_COMMON_SOURCES)
+ set(XR_COMMON_SOURCES)
+endif()
+
+if(NOT DEFINED XR_LIBS)
+ set(XR_LIBS)
+endif()
+
+if(NOT DEFINED XR_COMMON_PATH)
+ set(XR_COMMON_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../extensions/xr-plugin/common)
+endif()
+
+if(NOT DEFINED XR_LIBRARY_PATH)
+ set(XR_LIBRARY_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../extensions/xr-plugin/platforms)
+endif()
+
+include(${XR_COMMON_PATH}/xr.cmake)
diff --git a/gradle.properties b/gradle.properties
index c840969..0a78375 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -36,7 +36,7 @@ PROP_TARGET_SDK_VERSION=35
PROP_BUILD_TOOLS_VERSION=36.0.0
# Android Application Name
-PROP_APP_NAME=magotest
+PROP_APP_NAME=Klasik 101 Okey
# Instant App
PROP_ENABLE_INSTANT_APP=false
@@ -44,24 +44,25 @@ PROP_ENABLE_INSTANT_APP=false
# InputSDK
PROP_ENABLE_INPUTSDK=false
-PROP_NDK_VERSION=29.0.14206865
+PROP_NDK_VERSION=25.2.9519653
-PROP_ENABLE_COMPRESS_SO=true
+
+PROP_ENABLE_COMPRESS_SO=false
# Build variant
-PROP_IS_DEBUG=false
+PROP_IS_DEBUG=true
# Cocos Engine Path
COCOS_ENGINE_PATH=C:/ProgramData/cocos/editors/Creator/3.8.8/resources/resources/3d/engine/native
# Res path
-RES_PATH=E:/project/okey101_native_sm/okey/build/android
+RES_PATH=E:/project/okey_an_test
# Native source dir
-NATIVE_DIR=E:/project/okey101_native_sm/okey/native/engine/android
+NATIVE_DIR=E:/project/okey_an_test/android
# Application ID
-APPLICATION_ID=top.android.test
+APPLICATION_ID=com.ddddd.one
# List of CPU Archtexture to build that application with
# Available architextures (armeabi-v7a | arm64-v8a | x86 | x86_64)
diff --git a/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/AndroidManifest.xml b/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/AndroidManifest.xml
new file mode 100644
index 0000000..8f53dcc
--- /dev/null
+++ b/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/output-metadata.json b/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/output-metadata.json
new file mode 100644
index 0000000..a601f77
--- /dev/null
+++ b/libservice/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/output-metadata.json
@@ -0,0 +1,18 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "AAPT_FRIENDLY_MERGED_MANIFESTS",
+ "kind": "Directory"
+ },
+ "applicationId": "com.cocos.service",
+ "variantName": "release",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "outputFile": "AndroidManifest.xml"
+ }
+ ],
+ "elementType": "File"
+}
\ No newline at end of file
diff --git a/libservice/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar b/libservice/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar
new file mode 100644
index 0000000..5da6a5d
Binary files /dev/null and b/libservice/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar differ
diff --git a/libservice/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties b/libservice/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties
new file mode 100644
index 0000000..1211b1e
--- /dev/null
+++ b/libservice/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties
@@ -0,0 +1,6 @@
+aarFormatVersion=1.0
+aarMetadataVersion=1.0
+minCompileSdk=1
+minCompileSdkExtension=0
+minAndroidGradlePluginVersion=1.0.0
+coreLibraryDesugaringEnabled=false
diff --git a/libservice/build/intermediates/annotation_processor_list/release/javaPreCompileRelease/annotationProcessors.json b/libservice/build/intermediates/annotation_processor_list/release/javaPreCompileRelease/annotationProcessors.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/libservice/build/intermediates/annotation_processor_list/release/javaPreCompileRelease/annotationProcessors.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/.gradle/8.11.1/gc.properties b/libservice/build/intermediates/annotations_typedef_file/release/extractReleaseAnnotations/typedefs.txt
similarity index 100%
rename from .gradle/8.11.1/gc.properties
rename to libservice/build/intermediates/annotations_typedef_file/release/extractReleaseAnnotations/typedefs.txt
diff --git a/libservice/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar b/libservice/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar
new file mode 100644
index 0000000..af23911
Binary files /dev/null and b/libservice/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar differ
diff --git a/libservice/build/intermediates/compile_r_class_jar/release/generateReleaseRFile/R.jar b/libservice/build/intermediates/compile_r_class_jar/release/generateReleaseRFile/R.jar
new file mode 100644
index 0000000..e301975
Binary files /dev/null and b/libservice/build/intermediates/compile_r_class_jar/release/generateReleaseRFile/R.jar differ
diff --git a/.gradle/vcs-1/gc.properties b/libservice/build/intermediates/compile_symbol_list/release/generateReleaseRFile/R.txt
similarity index 100%
rename from .gradle/vcs-1/gc.properties
rename to libservice/build/intermediates/compile_symbol_list/release/generateReleaseRFile/R.txt
diff --git a/libservice/build/intermediates/default_proguard_files/global/proguard-android-optimize.txt-8.10.1 b/libservice/build/intermediates/default_proguard_files/global/proguard-android-optimize.txt-8.10.1
new file mode 100644
index 0000000..5a3e3a5
--- /dev/null
+++ b/libservice/build/intermediates/default_proguard_files/global/proguard-android-optimize.txt-8.10.1
@@ -0,0 +1,89 @@
+# This is a configuration file for ProGuard.
+# http://proguard.sourceforge.net/index.html#manual/usage.html
+#
+# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
+# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
+# will be ignored by new version of the Android plugin for Gradle.
+
+# Optimizations: If you don't want to optimize, use the proguard-android.txt configuration file
+# instead of this one, which turns off the optimization flags.
+-allowaccessmodification
+
+# Preserve some attributes that may be required for reflection.
+-keepattributes AnnotationDefault,
+ EnclosingMethod,
+ InnerClasses,
+ RuntimeVisibleAnnotations,
+ RuntimeVisibleParameterAnnotations,
+ RuntimeVisibleTypeAnnotations,
+ Signature
+
+-keep public class com.google.vending.licensing.ILicensingService
+-keep public class com.android.vending.licensing.ILicensingService
+-keep public class com.google.android.vending.licensing.ILicensingService
+-dontnote com.android.vending.licensing.ILicensingService
+-dontnote com.google.vending.licensing.ILicensingService
+-dontnote com.google.android.vending.licensing.ILicensingService
+
+# For native methods, see https://www.guardsquare.com/manual/configuration/examples#native
+-keepclasseswithmembernames,includedescriptorclasses class * {
+ native ;
+}
+
+# Keep setters in Views so that animations can still work.
+-keepclassmembers public class * extends android.view.View {
+ void set*(***);
+ *** get*();
+}
+
+# We want to keep methods in Activity that could be used in the XML attribute onClick.
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+# For enumeration classes, see https://www.guardsquare.com/manual/configuration/examples#enumerations
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keepclassmembers class * implements android.os.Parcelable {
+ public static final ** CREATOR;
+}
+
+# Preserve annotated Javascript interface methods.
+-keepclassmembers class * {
+ @android.webkit.JavascriptInterface ;
+}
+
+# The support libraries contains references to newer platform versions.
+# Don't warn about those in case this app is linking against an older
+# platform version. We know about them, and they are safe.
+-dontnote android.support.**
+-dontnote androidx.**
+-dontwarn android.support.**
+-dontwarn androidx.**
+
+# Understand the @Keep support annotation.
+-keep class android.support.annotation.Keep
+
+-keep @android.support.annotation.Keep class * {*;}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep (...);
+}
+
+# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
+-dontnote org.apache.http.**
+-dontnote android.net.http.**
+
+# These classes are duplicated between android.jar and core-lambda-stubs.jar.
+-dontnote java.lang.invoke.**
diff --git a/libservice/build/intermediates/default_proguard_files/global/proguard-android.txt-8.10.1 b/libservice/build/intermediates/default_proguard_files/global/proguard-android.txt-8.10.1
new file mode 100644
index 0000000..6f7e4ef
--- /dev/null
+++ b/libservice/build/intermediates/default_proguard_files/global/proguard-android.txt-8.10.1
@@ -0,0 +1,95 @@
+# This is a configuration file for ProGuard.
+# http://proguard.sourceforge.net/index.html#manual/usage.html
+#
+# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
+# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
+# will be ignored by new version of the Android plugin for Gradle.
+
+# Optimization is turned off by default. Dex does not like code run
+# through the ProGuard optimize steps (and performs some
+# of these optimizations on its own).
+# Note that if you want to enable optimization, you cannot just
+# include optimization flags in your own project configuration file;
+# instead you will need to point to the
+# "proguard-android-optimize.txt" file instead of this one from your
+# project.properties file.
+-dontoptimize
+
+# Preserve some attributes that may be required for reflection.
+-keepattributes AnnotationDefault,
+ EnclosingMethod,
+ InnerClasses,
+ RuntimeVisibleAnnotations,
+ RuntimeVisibleParameterAnnotations,
+ RuntimeVisibleTypeAnnotations,
+ Signature
+
+-keep public class com.google.vending.licensing.ILicensingService
+-keep public class com.android.vending.licensing.ILicensingService
+-keep public class com.google.android.vending.licensing.ILicensingService
+-dontnote com.android.vending.licensing.ILicensingService
+-dontnote com.google.vending.licensing.ILicensingService
+-dontnote com.google.android.vending.licensing.ILicensingService
+
+# For native methods, see https://www.guardsquare.com/manual/configuration/examples#native
+-keepclasseswithmembernames,includedescriptorclasses class * {
+ native ;
+}
+
+# Keep setters in Views so that animations can still work.
+-keepclassmembers public class * extends android.view.View {
+ void set*(***);
+ *** get*();
+}
+
+# We want to keep methods in Activity that could be used in the XML attribute onClick.
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+# For enumeration classes, see https://www.guardsquare.com/manual/configuration/examples#enumerations
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keepclassmembers class * implements android.os.Parcelable {
+ public static final ** CREATOR;
+}
+
+# Preserve annotated Javascript interface methods.
+-keepclassmembers class * {
+ @android.webkit.JavascriptInterface ;
+}
+
+# The support libraries contains references to newer platform versions.
+# Don't warn about those in case this app is linking against an older
+# platform version. We know about them, and they are safe.
+-dontnote android.support.**
+-dontnote androidx.**
+-dontwarn android.support.**
+-dontwarn androidx.**
+
+# Understand the @Keep support annotation.
+-keep class android.support.annotation.Keep
+
+-keep @android.support.annotation.Keep class * {*;}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep (...);
+}
+
+# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
+-dontnote org.apache.http.**
+-dontnote android.net.http.**
+
+# These classes are duplicated between android.jar and core-lambda-stubs.jar.
+-dontnote java.lang.invoke.**
diff --git a/libservice/build/intermediates/default_proguard_files/global/proguard-defaults.txt-8.10.1 b/libservice/build/intermediates/default_proguard_files/global/proguard-defaults.txt-8.10.1
new file mode 100644
index 0000000..7bbb228
--- /dev/null
+++ b/libservice/build/intermediates/default_proguard_files/global/proguard-defaults.txt-8.10.1
@@ -0,0 +1,89 @@
+# This is a configuration file for ProGuard.
+# http://proguard.sourceforge.net/index.html#manual/usage.html
+#
+# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
+# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
+# will be ignored by new version of the Android plugin for Gradle.
+
+# Optimizations can be turned on and off in the 'postProcessing' DSL block.
+# The configuration below is applied if optimizations are enabled.
+-allowaccessmodification
+
+# Preserve some attributes that may be required for reflection.
+-keepattributes AnnotationDefault,
+ EnclosingMethod,
+ InnerClasses,
+ RuntimeVisibleAnnotations,
+ RuntimeVisibleParameterAnnotations,
+ RuntimeVisibleTypeAnnotations,
+ Signature
+
+-keep public class com.google.vending.licensing.ILicensingService
+-keep public class com.android.vending.licensing.ILicensingService
+-keep public class com.google.android.vending.licensing.ILicensingService
+-dontnote com.android.vending.licensing.ILicensingService
+-dontnote com.google.vending.licensing.ILicensingService
+-dontnote com.google.android.vending.licensing.ILicensingService
+
+# For native methods, see https://www.guardsquare.com/manual/configuration/examples#native
+-keepclasseswithmembernames,includedescriptorclasses class * {
+ native ;
+}
+
+# Keep setters in Views so that animations can still work.
+-keepclassmembers public class * extends android.view.View {
+ void set*(***);
+ *** get*();
+}
+
+# We want to keep methods in Activity that could be used in the XML attribute onClick.
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+# For enumeration classes, see https://www.guardsquare.com/manual/configuration/examples#enumerations
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keepclassmembers class * implements android.os.Parcelable {
+ public static final ** CREATOR;
+}
+
+# Preserve annotated Javascript interface methods.
+-keepclassmembers class * {
+ @android.webkit.JavascriptInterface ;
+}
+
+# The support libraries contains references to newer platform versions.
+# Don't warn about those in case this app is linking against an older
+# platform version. We know about them, and they are safe.
+-dontnote android.support.**
+-dontnote androidx.**
+-dontwarn android.support.**
+-dontwarn androidx.**
+
+# Understand the @Keep support annotation.
+-keep class android.support.annotation.Keep
+
+-keep @android.support.annotation.Keep class * {*;}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @android.support.annotation.Keep (...);
+}
+
+# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
+-dontnote org.apache.http.**
+-dontnote android.net.http.**
+
+# These classes are duplicated between android.jar and core-lambda-stubs.jar.
+-dontnote java.lang.invoke.**
diff --git a/libservice/build/intermediates/full_jar/release/createFullJarRelease/full.jar b/libservice/build/intermediates/full_jar/release/createFullJarRelease/full.jar
new file mode 100644
index 0000000..6fb8259
Binary files /dev/null and b/libservice/build/intermediates/full_jar/release/createFullJarRelease/full.jar differ
diff --git a/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/module.xml b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/module.xml
new file mode 100644
index 0000000..51ce3aa
--- /dev/null
+++ b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/module.xml
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml
new file mode 100644
index 0000000..75ba889
--- /dev/null
+++ b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml
new file mode 100644
index 0000000..3cc905f
--- /dev/null
+++ b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release.xml b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release.xml
new file mode 100644
index 0000000..a9638ca
--- /dev/null
+++ b/libservice/build/intermediates/incremental/lintVitalAnalyzeRelease/release.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/incremental/mergeReleaseAssets/merger.xml b/libservice/build/intermediates/incremental/mergeReleaseAssets/merger.xml
new file mode 100644
index 0000000..61d59c6
--- /dev/null
+++ b/libservice/build/intermediates/incremental/mergeReleaseAssets/merger.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml b/libservice/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml
new file mode 100644
index 0000000..14b7453
--- /dev/null
+++ b/libservice/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/incremental/mergeReleaseShaders/merger.xml b/libservice/build/intermediates/incremental/mergeReleaseShaders/merger.xml
new file mode 100644
index 0000000..e3ad3ed
--- /dev/null
+++ b/libservice/build/intermediates/incremental/mergeReleaseShaders/merger.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/incremental/release-mergeJavaRes/merge-state b/libservice/build/intermediates/incremental/release-mergeJavaRes/merge-state
new file mode 100644
index 0000000..1c983fc
Binary files /dev/null and b/libservice/build/intermediates/incremental/release-mergeJavaRes/merge-state differ
diff --git a/libservice/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties b/libservice/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties
new file mode 100644
index 0000000..eb7653a
--- /dev/null
+++ b/libservice/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties
@@ -0,0 +1 @@
+#Tue Mar 10 16:09:39 CST 2026
diff --git a/libservice/build/intermediates/incremental/release/packageReleaseResources/merger.xml b/libservice/build/intermediates/incremental/release/packageReleaseResources/merger.xml
new file mode 100644
index 0000000..6b49f2f
--- /dev/null
+++ b/libservice/build/intermediates/incremental/release/packageReleaseResources/merger.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$1.class b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$1.class
new file mode 100644
index 0000000..8421648
Binary files /dev/null and b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$1.class differ
diff --git a/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKInterface.class b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKInterface.class
new file mode 100644
index 0000000..3628038
Binary files /dev/null and b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKInterface.class differ
diff --git a/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKWrapperInstance.class b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKWrapperInstance.class
new file mode 100644
index 0000000..3fa8a9b
Binary files /dev/null and b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper$SDKWrapperInstance.class differ
diff --git a/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper.class b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper.class
new file mode 100644
index 0000000..e04780d
Binary files /dev/null and b/libservice/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/cocos/service/SDKWrapper.class differ
diff --git a/libservice/build/intermediates/lint-cache/lintVitalAnalyzeRelease/lint-cache-version.txt b/libservice/build/intermediates/lint-cache/lintVitalAnalyzeRelease/lint-cache-version.txt
new file mode 100644
index 0000000..0b53a2d
--- /dev/null
+++ b/libservice/build/intermediates/lint-cache/lintVitalAnalyzeRelease/lint-cache-version.txt
@@ -0,0 +1 @@
+Cache for Android Lint31.10.1
diff --git a/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/module.xml b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/module.xml
new file mode 100644
index 0000000..51ce3aa
--- /dev/null
+++ b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/module.xml
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml
new file mode 100644
index 0000000..19a761e
--- /dev/null
+++ b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml
new file mode 100644
index 0000000..8094328
--- /dev/null
+++ b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release.xml b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release.xml
new file mode 100644
index 0000000..d025e5b
--- /dev/null
+++ b/libservice/build/intermediates/lint_model/release/generateReleaseLintModel/release.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_model_metadata/release/writeReleaseLintModelMetadata/lint-model-metadata.properties b/libservice/build/intermediates/lint_model_metadata/release/writeReleaseLintModelMetadata/lint-model-metadata.properties
new file mode 100644
index 0000000..cd8efb2
--- /dev/null
+++ b/libservice/build/intermediates/lint_model_metadata/release/writeReleaseLintModelMetadata/lint-model-metadata.properties
@@ -0,0 +1,3 @@
+mavenArtifactId=libservice
+mavenGroupId=magotest
+mavenVersion=unspecified
\ No newline at end of file
diff --git a/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/module.xml b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/module.xml
new file mode 100644
index 0000000..51ce3aa
--- /dev/null
+++ b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/module.xml
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml
new file mode 100644
index 0000000..19a761e
--- /dev/null
+++ b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml
new file mode 100644
index 0000000..8094328
--- /dev/null
+++ b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release.xml b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release.xml
new file mode 100644
index 0000000..abcad71
--- /dev/null
+++ b/libservice/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libservice/build/intermediates/lint_vital_partial_results/release/lintVitalAnalyzeRelease/out/lint-resources.xml b/libservice/build/intermediates/lint_vital_partial_results/release/lintVitalAnalyzeRelease/out/lint-resources.xml
new file mode 100644
index 0000000..e69de29
diff --git a/libservice/build/intermediates/local_aar_for_lint/release/out.aar b/libservice/build/intermediates/local_aar_for_lint/release/out.aar
new file mode 100644
index 0000000..b0e4fcf
Binary files /dev/null and b/libservice/build/intermediates/local_aar_for_lint/release/out.aar differ
diff --git a/libservice/build/intermediates/local_only_symbol_list/release/parseReleaseLocalResources/R-def.txt b/libservice/build/intermediates/local_only_symbol_list/release/parseReleaseLocalResources/R-def.txt
new file mode 100644
index 0000000..78ac5b8
--- /dev/null
+++ b/libservice/build/intermediates/local_only_symbol_list/release/parseReleaseLocalResources/R-def.txt
@@ -0,0 +1,2 @@
+R_DEF: Internal format may change without notice
+local
diff --git a/libservice/build/intermediates/manifest_merge_blame_file/release/processReleaseManifest/manifest-merger-blame-release-report.txt b/libservice/build/intermediates/manifest_merge_blame_file/release/processReleaseManifest/manifest-merger-blame-release-report.txt
new file mode 100644
index 0000000..1aa59dc
--- /dev/null
+++ b/libservice/build/intermediates/manifest_merge_blame_file/release/processReleaseManifest/manifest-merger-blame-release-report.txt
@@ -0,0 +1,7 @@
+1
+2
+4
+5
+6
+7
diff --git a/libservice/build/intermediates/merged_java_res/release/mergeReleaseJavaResource/feature-libservice.jar b/libservice/build/intermediates/merged_java_res/release/mergeReleaseJavaResource/feature-libservice.jar
new file mode 100644
index 0000000..15cb0ec
Binary files /dev/null and b/libservice/build/intermediates/merged_java_res/release/mergeReleaseJavaResource/feature-libservice.jar differ
diff --git a/libservice/build/intermediates/merged_manifest/release/processReleaseManifest/AndroidManifest.xml b/libservice/build/intermediates/merged_manifest/release/processReleaseManifest/AndroidManifest.xml
new file mode 100644
index 0000000..8f53dcc
--- /dev/null
+++ b/libservice/build/intermediates/merged_manifest/release/processReleaseManifest/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libservice/build/intermediates/navigation_json/release/extractDeepLinksRelease/navigation.json b/libservice/build/intermediates/navigation_json/release/extractDeepLinksRelease/navigation.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/libservice/build/intermediates/navigation_json/release/extractDeepLinksRelease/navigation.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/libservice/build/intermediates/nested_resources_validation_report/release/generateReleaseResources/nestedResourcesValidationReport.txt b/libservice/build/intermediates/nested_resources_validation_report/release/generateReleaseResources/nestedResourcesValidationReport.txt
new file mode 100644
index 0000000..08f4ebe
--- /dev/null
+++ b/libservice/build/intermediates/nested_resources_validation_report/release/generateReleaseResources/nestedResourcesValidationReport.txt
@@ -0,0 +1 @@
+0 Warning/Error
\ No newline at end of file
diff --git a/libservice/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar b/libservice/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar
new file mode 100644
index 0000000..11fc624
Binary files /dev/null and b/libservice/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar differ
diff --git a/libservice/build/intermediates/symbol_list_with_package_name/release/generateReleaseRFile/package-aware-r.txt b/libservice/build/intermediates/symbol_list_with_package_name/release/generateReleaseRFile/package-aware-r.txt
new file mode 100644
index 0000000..d98b5bc
--- /dev/null
+++ b/libservice/build/intermediates/symbol_list_with_package_name/release/generateReleaseRFile/package-aware-r.txt
@@ -0,0 +1 @@
+com.cocos.service
diff --git a/libservice/build/outputs/logs/manifest-merger-release-report.txt b/libservice/build/outputs/logs/manifest-merger-release-report.txt
new file mode 100644
index 0000000..9e55c87
--- /dev/null
+++ b/libservice/build/outputs/logs/manifest-merger-release-report.txt
@@ -0,0 +1,16 @@
+-- Merging decision tree log ---
+manifest
+ADDED from E:\project\okey_an_test\libservice\AndroidManifest.xml:1:1-3:12
+INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml:1:1-3:12
+ package
+ INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml
+ xmlns:android
+ ADDED from E:\project\okey_an_test\libservice\AndroidManifest.xml:1:11-69
+uses-sdk
+INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml reason: use-sdk injection requested
+INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml
+INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml
+ android:targetSdkVersion
+ INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml
+ android:minSdkVersion
+ INJECTED from E:\project\okey_an_test\libservice\AndroidManifest.xml
diff --git a/libservice/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin b/libservice/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin
new file mode 100644
index 0000000..0bc14e7
Binary files /dev/null and b/libservice/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin differ