エラーの理由
今日もコーディングの日です。
人生初のプロジェクトがフラッシュバックして、呼び戻されました。とても不快でした。開いたらフラッシュバックしました。後になって、携帯電話の IMEI を申請するためにアプリを開いたことに突然気づきましたデフォルトでは電話です。テストに使用した携帯電話は私が手動で開いたものです。そのため、この問題には注意していませんでした。
案の定、ログにはエラーが報告されています。
java.lang.SecurityException: getDeviceId: The user 10368 does not meet the requirements to access device identifiers.
場所は、AndroidMainfest.xml のグローバル クラスであるアプリケーション内にあります。
<application
android:name=".OverallSituation"
グローバルクラスのonCreateで以下のメソッドを実行しました
public String getDevice(Context context){
try {
TelephonyManager tm =
(TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
return tm.getDeviceId();
}else {
Method method = tm.getClass().getMethod("getImei");
return (String) method.invoke(tm);
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
動的に権限を取得する
このとき、ユーザーの許可を通じて IMEI を動的に取得する必要があります
。!!
著作権に関する声明: この記事は CSDN ブロガー「ZhangQiang-」のオリジナル記事であり、CC 4.0 BY-SA 著作権契約に従って、転載する場合は元のソースリンクとこの声明を添付してください。
原文リンク: https://blog.csdn.net/u011200604/article/details/52874599
特別な許可
CALENDAR カレンダー
CAMERA カメラ
CONTACTS 連絡先担当者
LOCATION
測位 MICROPHONE 録音などのマイク関連
PHONE 携帯電話の状態
SENSORS センサー
SMS テキスト メッセージSTORAGE
ストレージ
例えば、携帯電話の固有識別コードを読み取りたい場合は、PHONEのREAD_PHONE_STATEを取得する必要があるので、
それをMainActivityに追加して(ユーザーがAPPに入るときに許可の申請を開始します)実行します。onCreateで
public boolean getIMEI(final Activity activity, Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.READ_PHONE_STATE)) {
Log.i(TAG, "getIMEI: 再次申请授权");
//自定义弹窗获取
new AlertDialog.Builder(context)
.setMessage("需要开启权限才能正常使用")
.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//引导用户到设置中去进行设置
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", getPackageName(), null));
activity.startActivity(intent);
}
})
.setNegativeButton("取消", null)
.create()
.show();
} else {
Log.i(TAG, "getIMEI: 申请授权");
//没有授权
ActivityCompat.requestPermissions(activity, new String[]{
Manifest.permission.READ_PHONE_STATE}, PERMISSION_REQUESTCODE);
}
return false;
}
return true;
}
getIMEI(this,this);//onCreate中添加
さらに、AndroidMainfest.xml に相対権限を追加します。
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
設定に移動し、アプリケーションに携帯電話情報のアクセス許可設定を取得するように依頼すると、次の図が表示されます。[
許可] をクリックすると、対応するアクセス許可情報を取得できます。[
拒否] をクリックすると、
ポップアップ ウィンドウが表示され、ユーザーに要求が表示されます。
ステータスの取得にはシーンの要件を確認する必要があります
。カメラを開くにはコードをスキャンする必要があり、許可を拒否するとユーザーはこの機能を使用できなくなります
以下はMIUI用に空の情報を返す処理(独自のデバイスコードのカスタマイズ生成)です。
ツール クラス、ソースが見つかりません。侵害については私に連絡してください。
/**
* @author xc
* @date 2018/11/16
* @desc
*/
public class DeviceIdUtil {
/**
* 获得设备硬件标识
*
* @param context 上下文
* @return 设备硬件标识
*/
public static String getDeviceId(Context context) {
StringBuilder sbDeviceId = new StringBuilder();
//获得设备默认IMEI(>=6.0 需要ReadPhoneState权限)
String imei = getIMEI(context);
//获得AndroidId(无需权限)
String androidid = getAndroidId(context);
//获得设备序列号(无需权限)
String serial = getSERIAL();
//获得硬件uuid(根据硬件相关属性,生成uuid)(无需权限)
String uuid = getDeviceUUID().replace("-", "");
//追加imei
if (imei != null && imei.length() > 0) {
sbDeviceId.append(imei);
sbDeviceId.append("|");
}
//追加androidid
if (androidid != null && androidid.length() > 0) {
sbDeviceId.append(androidid);
sbDeviceId.append("|");
}
//追加serial
if (serial != null && serial.length() > 0) {
sbDeviceId.append(serial);
sbDeviceId.append("|");
}
//追加硬件uuid
if (uuid != null && uuid.length() > 0) {
sbDeviceId.append(uuid);
}
//生成SHA1,统一DeviceId长度
if (sbDeviceId.length() > 0) {
try {
byte[] hash = getHashByString(sbDeviceId.toString());
String sha1 = bytesToHex(hash);
if (sha1 != null && sha1.length() > 0) {
//返回最终的DeviceId
return sha1;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
//如果以上硬件标识数据均无法获得,
//则DeviceId默认使用系统随机数,这样保证DeviceId不为空
return UUID.randomUUID().toString().replace("-", "");
}
//需要获得READ_PHONE_STATE权限,>=6.0,默认返回null
private static String getIMEI(Context context) {
try {
TelephonyManager tm = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getDeviceId();
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获得设备的AndroidId
*
* @param context 上下文
* @return 设备的AndroidId
*/
private static String getAndroidId(Context context) {
try {
return Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.ANDROID_ID);
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获得设备序列号(如:WTK7N16923005607), 个别设备无法获取
*
* @return 设备序列号
*/
private static String getSERIAL() {
try {
return Build.SERIAL;
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获得设备硬件uuid
* 使用硬件信息,计算出一个随机数
*
* @return 设备硬件uuid
*/
private static String getDeviceUUID() {
try {
String dev = "3883756" +
Build.BOARD.length() % 10 +
Build.BRAND.length() % 10 +
Build.DEVICE.length() % 10 +
Build.HARDWARE.length() % 10 +
Build.ID.length() % 10 +
Build.MODEL.length() % 10 +
Build.PRODUCT.length() % 10 +
Build.SERIAL.length() % 10;
return new UUID(dev.hashCode(),
Build.SERIAL.hashCode()).toString();
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
/**
* 取SHA1
* @param data 数据
* @return 对应的hash值
*/
private static byte[] getHashByString(String data)
{
try{
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.reset();
messageDigest.update(data.getBytes("UTF-8"));
return messageDigest.digest();
} catch (Exception e){
return "".getBytes();
}
}
/**
* 转16进制字符串
* @param data 数据
* @return 16进制字符串
*/
private static String bytesToHex(byte[] data){
StringBuilder sb = new StringBuilder();
String stmp;
for (int n = 0; n < data.length; n++){
stmp = (Integer.toHexString(data[n] & 0xFF));
if (stmp.length() == 1)
sb.append("0");
sb.append(stmp);
}
return sb.toString().toUpperCase(Locale.CHINA);
}
}