diff --git a/app/build.gradle b/app/build.gradle
index 4e84a744..e11bcf0c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,9 +27,9 @@ android {
versionCode versionProps['versionCode'].toInteger()
versionName versionProps['versionName']
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
- //ndk {
- // abiFilters 'armeabi-v7a', 'x86_64'
- //}
+ ndk {
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'//, 'x86_64'
+ }
}
lintOptions {
checkReleaseBuilds false
@@ -67,11 +67,11 @@ android {
abi {
enable true
reset()
- include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
+ include 'armeabi-v7a', 'arm64-v8a', 'x86'//, 'x86_64'
universalApk true
}
}
- def abiCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4, 'universal': 5]
+ def abiCodes = ['universal': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'x86': 4, 'x86_64': 5]
android.applicationVariants.all { variant ->
// Assigns a different version code for each output APK.
variant.outputs.each {
@@ -79,7 +79,7 @@ android {
def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08"))
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
if (abiName == null) abiName = "universal"
- output.versionCodeOverride = abiCodes.get(abiName, 0) * 10000 + variant.versionCode
+ output.versionCodeOverride = abiCodes.get(abiName, 0) * 100000 + variant.versionCode
output.outputFileName = "SmsForwarder_${variant.name}_${versionName}_${output.versionCodeOverride}_${date}_${abiName}.apk"
}
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c2d85abf..cd89c021 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -40,6 +40,9 @@
+
+
+
permissions, boolean all) {
+ if (all) {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_all, Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_part, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(true);
+ }
+
+ @Override
+ public void onDenied(List permissions, boolean never) {
+ if (never) {
+ Toast.makeText(getBaseContext(), R.string.toast_denied_never, Toast.LENGTH_SHORT).show();
+ // 如果是被永久拒绝就跳转到应用权限系统设置页面
+ XXPermissions.startPermissionActivity(AboutActivity.this, permissions);
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_denied, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(false);
+ }
+ });
+
final TextView version_now = findViewById(R.id.version_now);
Button check_version_now = findViewById(R.id.check_version_now);
try {
diff --git a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java b/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java
index d9d78cd4..b9e772c4 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java
+++ b/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java
@@ -27,6 +27,9 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.hjq.permissions.OnPermissionCallback;
+import com.hjq.permissions.Permission;
+import com.hjq.permissions.XXPermissions;
import com.idormy.sms.forwarder.adapter.LogAdapter;
import com.idormy.sms.forwarder.model.vo.LogVo;
import com.idormy.sms.forwarder.sender.HttpServer;
@@ -140,6 +143,53 @@ public class MainActivity extends AppCompatActivity implements RefreshListView.I
//检查权限是否获取
PackageManager pm = getPackageManager();
CommonUtil.CheckPermission(pm, this);
+ XXPermissions.with(this)
+ // 接收短信
+ .permission(Permission.RECEIVE_SMS)
+ // 发送短信
+ .permission(Permission.SEND_SMS)
+ // 读取短信
+ .permission(Permission.READ_SMS)
+ // 读取电话状态
+ .permission(Permission.READ_PHONE_STATE)
+ // 读取手机号码
+ .permission(Permission.READ_PHONE_NUMBERS)
+ // 读取通话记录
+ .permission(Permission.READ_CALL_LOG)
+ // 读取联系人
+ .permission(Permission.READ_CONTACTS)
+ // 储存权限
+ .permission(Permission.Group.STORAGE)
+ // 申请安装包权限
+ //.permission(Permission.REQUEST_INSTALL_PACKAGES)
+ // 申请通知栏权限
+ .permission(Permission.NOTIFICATION_SERVICE)
+ // 申请系统设置权限
+ //.permission(Permission.WRITE_SETTINGS)
+ .request(new OnPermissionCallback() {
+
+ @Override
+ public void onGranted(List permissions, boolean all) {
+ if (all) {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_all, Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_part, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(true);
+ }
+
+ @Override
+ public void onDenied(List permissions, boolean never) {
+ if (never) {
+ Toast.makeText(getBaseContext(), R.string.toast_denied_never, Toast.LENGTH_SHORT).show();
+ // 如果是被永久拒绝就跳转到应用权限系统设置页面
+ XXPermissions.startPermissionActivity(MainActivity.this, permissions);
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_denied, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(false);
+ }
+ });
//计算浮动按钮位置
FloatingActionButton btnFloat = findViewById(R.id.btnCleanLog);
diff --git a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java
index 804c6102..91adb2e7 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java
+++ b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java
@@ -10,11 +10,15 @@ import android.content.SharedPreferences;
import android.os.Build;
import android.util.Log;
+import com.hjq.permissions.XXPermissions;
+import com.hjq.toast.ToastUtils;
+import com.hjq.toast.style.WhiteToastStyle;
import com.idormy.sms.forwarder.receiver.SimStateReceiver;
import com.idormy.sms.forwarder.sender.SendHistory;
import com.idormy.sms.forwarder.service.BatteryService;
import com.idormy.sms.forwarder.service.FrontService;
import com.idormy.sms.forwarder.utils.Define;
+import com.idormy.sms.forwarder.utils.PermissionInterceptor;
import com.idormy.sms.forwarder.utils.PhoneUtils;
import com.idormy.sms.forwarder.utils.SettingUtil;
import com.idormy.sms.forwarder.utils.SharedPreferencesHelper;
@@ -51,6 +55,11 @@ public class MyApplication extends Application {
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext());
+ // 初始化吐司工具类
+ ToastUtils.init(this, new WhiteToastStyle());
+ // 设置权限申请拦截器(全局设置)
+ XXPermissions.setInterceptor(new PermissionInterceptor());
+
//友盟统计
sharedPreferencesHelper = new SharedPreferencesHelper(this, "umeng");
//设置LOG开关,默认为false
diff --git a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java b/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java
index 592257ee..542f4d0c 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java
+++ b/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java
@@ -28,6 +28,9 @@ import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
+import com.hjq.permissions.OnPermissionCallback;
+import com.hjq.permissions.Permission;
+import com.hjq.permissions.XXPermissions;
import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
import com.idormy.sms.forwarder.sender.HttpServer;
import com.idormy.sms.forwarder.sender.SenderUtil;
@@ -133,9 +136,45 @@ public class SettingActivity extends AppCompatActivity {
switch_enable_sms.setChecked(SettingUtil.getSwitchEnableSms());
switch_enable_sms.setOnCheckedChangeListener((buttonView, isChecked) -> {
- //TODO:校验使用短信转发必备的权限
- SettingUtil.switchEnableSms(isChecked);
Log.d(TAG, "switchEnableSms:" + isChecked);
+ if (isChecked) {
+ //检查权限是否获取
+ PackageManager pm = getPackageManager();
+ CommonUtil.CheckPermission(pm, this);
+ XXPermissions.with(this)
+ // 接收短信
+ .permission(Permission.RECEIVE_SMS)
+ // 发送短信
+ .permission(Permission.SEND_SMS)
+ // 读取短信
+ .permission(Permission.READ_SMS)
+ .request(new OnPermissionCallback() {
+
+ @Override
+ public void onGranted(List permissions, boolean all) {
+ if (all) {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_all, Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_part, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(true);
+ }
+
+ @Override
+ public void onDenied(List permissions, boolean never) {
+ if (never) {
+ Toast.makeText(getBaseContext(), R.string.toast_denied_never, Toast.LENGTH_SHORT).show();
+ // 如果是被永久拒绝就跳转到应用权限系统设置页面
+ XXPermissions.startPermissionActivity(SettingActivity.this, permissions);
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_denied, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(false);
+ }
+ });
+ } else {
+ SettingUtil.switchEnableSms(false);
+ }
});
}
@@ -154,9 +193,47 @@ public class SettingActivity extends AppCompatActivity {
return;
}
- //TODO:校验使用来电转发必备的权限
- SettingUtil.switchEnablePhone(isChecked);
Log.d(TAG, "switchEnablePhone:" + isChecked);
+ if (isChecked) {
+ //检查权限是否获取
+ PackageManager pm = getPackageManager();
+ CommonUtil.CheckPermission(pm, this);
+ XXPermissions.with(this)
+ // 读取电话状态
+ .permission(Permission.READ_PHONE_STATE)
+ // 读取手机号码
+ .permission(Permission.READ_PHONE_NUMBERS)
+ // 读取通话记录
+ .permission(Permission.READ_CALL_LOG)
+ // 读取联系人
+ .permission(Permission.READ_CONTACTS)
+ .request(new OnPermissionCallback() {
+
+ @Override
+ public void onGranted(List permissions, boolean all) {
+ if (all) {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_all, Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_granted_part, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(true);
+ }
+
+ @Override
+ public void onDenied(List permissions, boolean never) {
+ if (never) {
+ Toast.makeText(getBaseContext(), R.string.toast_denied_never, Toast.LENGTH_SHORT).show();
+ // 如果是被永久拒绝就跳转到应用权限系统设置页面
+ XXPermissions.startPermissionActivity(SettingActivity.this, permissions);
+ } else {
+ Toast.makeText(getBaseContext(), R.string.toast_denied, Toast.LENGTH_SHORT).show();
+ }
+ SettingUtil.switchEnableSms(false);
+ }
+ });
+ } else {
+ SettingUtil.switchEnablePhone(false);
+ }
});
check_box_call_type_1.setOnCheckedChangeListener((buttonView, isChecked) -> {
diff --git a/app/src/main/java/com/idormy/sms/forwarder/receiver/PhoneStateReceiver.java b/app/src/main/java/com/idormy/sms/forwarder/receiver/PhoneStateReceiver.java
index 7d0d382f..e0728fc2 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/receiver/PhoneStateReceiver.java
+++ b/app/src/main/java/com/idormy/sms/forwarder/receiver/PhoneStateReceiver.java
@@ -98,7 +98,7 @@ public class PhoneStateReceiver extends BroadcastReceiver {
String viaNumber = callInfo.getViaNumber(); //来源号码
//卡槽判断:获取卡槽失败时,默认为卡槽1
- String simInfo = "";
+ String simInfo;
int simId = 1;
Log.d(TAG, "getSubscriptionId = " + callInfo.getSubscriptionId()); //TODO:这里的SubscriptionId跟短信的不一样
if (callInfo.getSubscriptionId() != -1) {
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/PermissionInterceptor.java b/app/src/main/java/com/idormy/sms/forwarder/utils/PermissionInterceptor.java
new file mode 100644
index 00000000..1bf5fe14
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/PermissionInterceptor.java
@@ -0,0 +1,282 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.hjq.permissions.IPermissionInterceptor;
+import com.hjq.permissions.OnPermissionCallback;
+import com.hjq.permissions.Permission;
+import com.hjq.permissions.XXPermissions;
+import com.hjq.toast.ToastUtils;
+import com.idormy.sms.forwarder.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * author : Android 轮子哥
+ * github : https://github.com/getActivity/XXPermissions
+ * time : 2021/01/04
+ * desc : 权限申请拦截器
+ */
+@SuppressWarnings({"deprecation", "CommentedOutCode"})
+public final class PermissionInterceptor implements IPermissionInterceptor {
+
+// @Override
+// public void requestPermissions(Activity activity, OnPermissionCallback callback, List allPermissions) {
+// // 这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期
+// new AlertDialog.Builder(activity)
+// .setTitle(R.string.common_permission_hint)
+// .setMessage(R.string.common_permission_message)
+// .setPositiveButton(R.string.common_permission_granted, new DialogInterface.OnClickListener() {
+//
+// @Override
+// public void onClick(DialogInterface dialog, int which) {
+// dialog.dismiss();
+// PermissionFragment.beginRequest(activity, new ArrayList<>(allPermissions), PermissionInterceptor.this, callback);
+// }
+// })
+// .setNegativeButton(R.string.common_permission_denied, new DialogInterface.OnClickListener() {
+//
+// @Override
+// public void onClick(DialogInterface dialog, int which) {
+// dialog.dismiss();
+// }
+// })
+// .show();
+// }
+
+ @Override
+ public void grantedPermissions(Activity activity, List allPermissions, List grantedPermissions,
+ boolean all, OnPermissionCallback callback) {
+ if (callback != null) {
+ callback.onGranted(grantedPermissions, all);
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ @Override
+ public void deniedPermissions(Activity activity, List allPermissions, List deniedPermissions,
+ boolean never, OnPermissionCallback callback) {
+ if (callback != null) {
+ callback.onDenied(deniedPermissions, never);
+ }
+
+ if (never) {
+ showPermissionDialog(activity, deniedPermissions);
+ return;
+ }
+
+ if (deniedPermissions.size() == 1 && Permission.ACCESS_BACKGROUND_LOCATION.equals(deniedPermissions.get(0))) {
+ ToastUtils.show(R.string.common_permission_fail_4);
+ return;
+ }
+
+ ToastUtils.show(R.string.common_permission_fail_1);
+
+ if (callback == null) {
+ return;
+ }
+ callback.onDenied(deniedPermissions, never);
+ }
+
+ /**
+ * 显示授权对话框
+ */
+ protected void showPermissionDialog(Activity activity, List permissions) {
+ // 这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.common_permission_alert)
+ .setCancelable(false)
+ .setMessage(getPermissionHint(activity, permissions))
+ .setPositiveButton(R.string.common_permission_goto, (dialog, which) -> {
+ dialog.dismiss();
+ XXPermissions.startPermissionActivity(activity, permissions);
+ })
+ .show();
+ }
+
+ /**
+ * 根据权限获取提示
+ */
+ protected String getPermissionHint(Context context, List permissions) {
+ if (permissions == null || permissions.isEmpty()) {
+ return context.getString(R.string.common_permission_fail_2);
+ }
+
+ List hints = new ArrayList<>();
+ for (String permission : permissions) {
+ switch (permission) {
+ case Permission.READ_EXTERNAL_STORAGE:
+ case Permission.WRITE_EXTERNAL_STORAGE:
+ case Permission.MANAGE_EXTERNAL_STORAGE: {
+ String hint = context.getString(R.string.common_permission_storage);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.CAMERA: {
+ String hint = context.getString(R.string.common_permission_camera);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.RECORD_AUDIO: {
+ String hint = context.getString(R.string.common_permission_microphone);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.ACCESS_FINE_LOCATION:
+ case Permission.ACCESS_COARSE_LOCATION:
+ case Permission.ACCESS_BACKGROUND_LOCATION: {
+ String hint;
+ if (!permissions.contains(Permission.ACCESS_FINE_LOCATION) &&
+ !permissions.contains(Permission.ACCESS_COARSE_LOCATION)) {
+ hint = context.getString(R.string.common_permission_location_background);
+ } else {
+ hint = context.getString(R.string.common_permission_location);
+ }
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.BLUETOOTH_SCAN:
+ case Permission.BLUETOOTH_CONNECT:
+ case Permission.BLUETOOTH_ADVERTISE: {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ String hint = context.getString(R.string.common_permission_bluetooth);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ }
+ break;
+ }
+ case Permission.READ_PHONE_STATE:
+ case Permission.CALL_PHONE:
+ case Permission.ADD_VOICEMAIL:
+ case Permission.USE_SIP:
+ case Permission.READ_PHONE_NUMBERS:
+ case Permission.ANSWER_PHONE_CALLS: {
+ String hint = context.getString(R.string.common_permission_phone);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.GET_ACCOUNTS:
+ case Permission.READ_CONTACTS:
+ case Permission.WRITE_CONTACTS: {
+ String hint = context.getString(R.string.common_permission_contacts);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.READ_CALENDAR:
+ case Permission.WRITE_CALENDAR: {
+ String hint = context.getString(R.string.common_permission_calendar);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.READ_CALL_LOG:
+ case Permission.WRITE_CALL_LOG:
+ case Permission.PROCESS_OUTGOING_CALLS: {
+ String hint = context.getString(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
+ R.string.common_permission_call_log : R.string.common_permission_phone);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.BODY_SENSORS: {
+ String hint = context.getString(R.string.common_permission_sensors);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.ACTIVITY_RECOGNITION: {
+ String hint = context.getString(R.string.common_permission_activity_recognition);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.SEND_SMS:
+ case Permission.RECEIVE_SMS:
+ case Permission.READ_SMS:
+ case Permission.RECEIVE_WAP_PUSH:
+ case Permission.RECEIVE_MMS: {
+ String hint = context.getString(R.string.common_permission_sms);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.REQUEST_INSTALL_PACKAGES: {
+ String hint = context.getString(R.string.common_permission_install);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.SYSTEM_ALERT_WINDOW: {
+ String hint = context.getString(R.string.common_permission_window);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.WRITE_SETTINGS: {
+ String hint = context.getString(R.string.common_permission_setting);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.NOTIFICATION_SERVICE: {
+ String hint = context.getString(R.string.common_permission_notification);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ case Permission.PACKAGE_USAGE_STATS: {
+ String hint = context.getString(R.string.common_permission_task);
+ if (!hints.contains(hint)) {
+ hints.add(hint);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (!hints.isEmpty()) {
+ StringBuilder builder = new StringBuilder();
+ for (String text : hints) {
+ if (builder.length() == 0) {
+ builder.append(text);
+ } else {
+ builder.append("、")
+ .append(text);
+ }
+ }
+ builder.append(" ");
+ return context.getString(R.string.common_permission_fail_3, builder.toString());
+ }
+
+ return context.getString(R.string.common_permission_fail_2);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 5a4c3b2c..51a1e27f 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -424,4 +424,8 @@
系统设置权限
通知栏权限
查看使用情况权限
+ 获取所有必需的权限成功!
+ 获取部分权限成功,但部分权限未正常授予,APP部分功能可能受限!
+ 被永久拒绝授权,请前往系统设置手动授予权限!
+ 获取必需的权限失败,APP功能可能受限!
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f35cb212..20b3d843 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -423,4 +423,8 @@
系统设置权限
通知栏权限
查看使用情况权限
+ 获取所有必需的权限成功!
+ 获取部分权限成功,但部分权限未正常授予,APP部分功能可能受限!
+ 被永久拒绝授权,请前往系统设置手动授予权限!
+ 获取必需的权限失败,APP功能可能受限!