Wie implementiere ich Android 6.0-Laufzeitberechtigungen für vorhandene Anwendungen?
Ich habe eine vorhandene App, für die ich die Laufzeitberechtigungen für Android 6.0 implementieren möchte. Ich habe viele verschiedene Dinge über Laufzeitberechtigungen gelesen, aber ich kann mich einfach nicht um all die verschiedenen Schnipsel kümmern. Nichts, was ich gefunden habe, zeigt tatsächlich, wie dies in eine vorhandene Aktivität implementiert werden kann.
Andere PunkteWenn ich mein vorhandenes Anwendungs-Targeting-SDK v23 ausführe, wird der Berechtigungsfehler wie erwartet angezeigt. Der angezeigte Berechtigungsfehler ist jedoch nicht einmal eine von mir angeforderte Berechtigung. Ich habe die Berechtigung SEND_SMS in der Manifest-Datei, aber der Fehler, den ich erhalte, betrifft READ_SMS. Meine App läuft ohne READ_SMS auf einer älteren Version als 6.0.
Ich möchte, dass meine App beim Start der App um Erlaubnis bittet, da der einzige Zweck der App das Senden einer SMS-Nachricht ist. Ohne diese Erlaubnis gibt es keine andere Verwendung für die App.
FragenWie kann ich Runtime-Berechtigungen für SEND_SMS in meine vorhandene Aktivität implementieren, sobald die App gestartet wird?
Muss die Behandlung dieser Berechtigung in einem Hintergrundthread ausgeführt werden?
Brauche ich auch Berechtigungen für READ_SMS, da dies der Berechtigungsfehler ist, den es gibt (obwohl diese Berechtigung für meine App noch nie verwendet wurde)?
Meine vorhandene Aktivität: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);
}
}