我有一个现有的应用程序,我想实现Android 6.0的运行时权限。我在运行时权限上已经阅读了很多不同的东西,但我似乎无法围绕所有不同的代码片段。我找到的任何内容实际上都没有显示如何将其实现到现有的Activity中。
当我运行针对SDK v23的现有应用程序时,我得到了预期的权限错误,但我得到的权限错误甚至不是我请求的权限。我在Manifest文件中有SEND_SMS权限,但我得到的错误是READ_SMS。我的应用程序在6.0之前运行正常,没有READ_SMS。
我希望我的应用程序在应用程序启动后立即请求权限,因为该应用程序的唯一目的是发送短信,因此如果没有该权限,则该应用程序没有其他用途。
启动应用后,如何将SEND_SMS的运行时权限实施到现有的Activity中?
这些权限的处理是否需要在后台线程中运行?
我是否还需要READ_SMS的权限,因为这是它给出的权限错误(即使该权限从未在我的应用程序上使用过)?
public class MainActivity extends Activity implements OnClickListener {
SimpleCursorAdapter mAdapter;
AutoCompleteTextView txtContract;
EditText txtTrip;
EditText txtDate;
Button btnSend;
Button btnUpdate;
String today;
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
private static final String API_KEY = "abcxyz";
private static final String CONTRACT_REGEX = "^([a-zA-Z0-9_-]){5}$";
private static final String TRIP_REGEX = "^([a-zA-Z0-9_-]){1,10}$";
private static final String DATE_REGEX = "^\\d{2}\\/\\d{2}\\/\\d{4}$";
private static final String PHONE_NUMBER = "1234567890";
private static final String DATE_FORMAT = "MM/dd/yyyy";
private BroadcastReceiver sendBroadcastReceiver;
private BroadcastReceiver deliveryBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// TODO - IMPLEMENT RUNTIME PERMISSIONS FOR ANDROID >= 6.0
try {
// Initialize Views
txtContract = (AutoCompleteTextView) findViewById(R.id.txtContract);
txtTrip = (EditText) findViewById(R.id.txtTrip);
txtDate = (EditText) findViewById(R.id.txtDate);
btnSend = (Button) findViewById(R.id.btnSend);
btnUpdate = (Button) findViewById(R.id.btnUpdate);
// Set Listeners
txtDate.setOnClickListener(this);
btnSend.setOnClickListener(this);
btnUpdate.setOnClickListener(this);
// Set Date To Today And Format
final Calendar td = Calendar.getInstance();
int tYear = td.get(Calendar.YEAR);
int tMonth = td.get(Calendar.MONTH);
int tDay = td.get(Calendar.DAY_OF_MONTH);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH);
td.set(tYear, tMonth, tDay);
today = sdf.format(td.getTime());
txtDate.setText(today);
// Check If Device Is Capable Of Sending SMS
PackageManager pm = this.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) &&
!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA)) {
Toast.makeText(this, "Sorry, your device probably can't send SMS...",
Toast.LENGTH_SHORT).show();
}
// Send Receiver
sendBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "Requesting trip...", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(), "Generic failure", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(getBaseContext(), "No service", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(), "Null PDU", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(), "Radio off", Toast.LENGTH_SHORT).show();
break;
}
}
};
// Delivery Receiver
deliveryBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "Trip request successful.", Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "Trip request failed.", Toast.LENGTH_SHORT).show();
break;
}
}
};
// Register Receivers
registerReceiver(deliveryBroadcastReceiver, new IntentFilter(DELIVERED));
registerReceiver(sendBroadcastReceiver , new IntentFilter(SENT));
// Set Up Adapter For Autocomplete
initializeAutoCompleteAdapter();
}
catch (Exception ex) {
Toast.makeText(this, "Error in MainActivity.onCreate: " + ex.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
unregisterReceiver(sendBroadcastReceiver);
unregisterReceiver(deliveryBroadcastReceiver);
super.onDestroy();
}
// Auto Complete Adapter
public void initializeAutoCompleteAdapter() {
// Set Database Handler
final DBHelper DBHelper = new DBHelper(getBaseContext());
// Set Up Adapter For Autocomplete (This does not run on the main UI thread)
mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null,
new String[] { "contract" },
new int[] {android.R.id.text1},
0);
txtContract.setAdapter(mAdapter);
mAdapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
@Override
public CharSequence convertToString(Cursor cursor) {
final int colIndex = cursor.getColumnIndexOrThrow("contract");
return cursor.getString(colIndex);
}
});
mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence description) {
String strContract = txtContract.getText().toString();
return DBHelper.getContract(strContract);
}
});
}
// OnClickListener Handler
@Override
public void onClick(View v) {
// Handle Clicked View
switch (v.getId()) {
// Date Field
case R.id.txtDate:
// Get Current Date
final Calendar c = Calendar.getInstance();
c.set(c.get(Calendar.YEAR),c.get(Calendar.MONTH),c.get(Calendar.DAY_OF_MONTH),0,0,0);
int mYear = c.get(Calendar.YEAR);
int mMonth = c.get(Calendar.MONTH);
int mDay = c.get(Calendar.DAY_OF_MONTH);
// Set Up DatePicker Dialog
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
// Define A New Calendar For Formatting
final Calendar cf = Calendar.getInstance();
// Format Selected Date
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH);
cf.set(year,month,day);
String selectedDate = sdf.format(cf.getTime());
// Add Selected Date To EditText Field
txtDate.setText(selectedDate);
}
}, mYear, mMonth, mDay);
// Set Max Date
c.add(Calendar.DATE, 2);
c.add(Calendar.SECOND, -1);
datePickerDialog.getDatePicker().setMaxDate(c.getTimeInMillis());
// Set Min Date
c.add(Calendar.DAY_OF_MONTH,-5);
c.add(Calendar.SECOND, 1);
datePickerDialog.getDatePicker().setMinDate(c.getTimeInMillis());
// Display DatePicker
datePickerDialog.show();
break;
// Submit Button
case R.id.btnSend:
Boolean rval = true;
if (!Validation.isValid(txtContract, CONTRACT_REGEX, "Invalid Contract #", true)) rval = false;
if (!Validation.isValid(txtTrip, TRIP_REGEX, "Invalid Trip #", true)) rval = false;
if (!Validation.isValid(txtDate, DATE_REGEX, "Invalid Date", true)) rval = false;
if(rval) {
new ValidateAndSend(this).execute();
}
break;
// Update Contract DB
case R.id.btnUpdate:
TelephonyManager tMgr = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String mPhoneNumber = tMgr.getLine1Number();
new POSTAsync(this).execute(API_KEY, mPhoneNumber);
break;
}
}
// Validate And Send
class ValidateAndSend extends AsyncTask<String, String, Boolean>{
private final WeakReference<MainActivity> MainActivityWeakRef;
public ValidateAndSend(MainActivity mainActivity) {
super();
this.MainActivityWeakRef = new WeakReference<>(mainActivity);
}
// Define Variables
String strContract = txtContract.getText().toString();
String strTrip = txtTrip.getText().toString();
String strDate = txtDate.getText().toString();
String strMessage = strContract.concat("|").concat(strTrip).concat("|").concat(strDate);
Boolean rval = true;
@Override
protected void onPreExecute() {
}
@Override
protected Boolean doInBackground(String... contract) {
DBHelper DBHelper = new DBHelper(MainActivity.this);
if (DBHelper.validateContract(strContract) < 1) rval = false;
return rval;
}
@Override
protected void onPostExecute(Boolean rval){
if(rval){
// Hide Keyboard
View view = MainActivity.this.getCurrentFocus();
if(view != null){
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
if (MainActivityWeakRef.get() != null && !MainActivityWeakRef.get().isFinishing()) {
// Confirm Details
AlertDialog.Builder alert = new AlertDialog.Builder(MainActivity.this);
alert.setTitle("Confirm Trip");
alert.setMessage("CONTRACT: " + strContract + "\nTRIP: " + strTrip + "\nDATE: " + strDate);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Send SMS
sendSMS(PHONE_NUMBER, strMessage);
// Clear Fields
txtContract.setText("");
txtTrip.setText("");
txtDate.setText(today);
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Cancelled
}
});
// Show Alert
alert.show();
}
}
else{
txtContract.setError("Invalid contract #");
Toast.makeText(MainActivity.this, "You may need to update contracts.",
Toast.LENGTH_LONG).show();
}
}
}
// Send SMS
private void sendSMS(String phoneNumber, String message) {
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0, new Intent(DELIVERED), 0);
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
}
答案 0 :(得分:6)
Android 6.0的运行时权限模型主要分为部分
<强> 1。检查权限
<强> 2。申请许可
您可以在活动中为此项创建两种方法,如下所示
检查权限
private boolean checkPermission(){
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS);
if (result == PackageManager.PERMISSION_GRANTED){
return true;
} else {
return false;
}
}
请求权限
private void requestPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,Manifest.permission.READ_SMS)){
Toast.makeText(context,"Read Sms Allowed.",Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.READ_SMS},PERMISSION_REQUEST_CODE);
}
}
最后但并非最不重要的是,您需要覆盖 onRequestPermissionsResult 方法
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Snackbar.make(view,"Permission Granted, Now you can access SMS.",Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(view,"Permission Denied, You cannot access SMS.",Snackbar.LENGTH_LONG).show();
}
break;
}
}
当你问我是否需要在线程中运行..答案是否只需在主线程中执行此操作
答案 1 :(得分:0)
如果您想减少代码,请使用Dexter是一个Android库,它简化了在运行时请求权限的过程。