我想发送电子邮件,如下面的代码:
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.support.design.widget.Snackbar;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import com.etf.jhilal.etf.Fragments.ZDDFragment;
import com.etf.jhilal.etf.Other.InternetDetector;
import com.etf.jhilal.etf.R;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.model.Message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
public class GmailSend extends AsyncTask<Void, Void, String> {
private com.google.api.services.gmail.Gmail mService = null;
private FragmentActivity activity;
private Exception mLastError = null;
private GoogleAccountCredential mCredential;
private ProgressDialog mprogress;
private Context mctx;
private String subject;
private String body;
public GmailSend(FragmentActivity activity, GoogleAccountCredential credential, final Context ctx, String sub, String bod) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.gmail.Gmail.Builder(
transport, jsonFactory, credential)
.setApplicationName(String.valueOf((R.string.app_name)))
.build();
this.activity = activity;
this.mCredential = credential;
this.mctx = ctx;
this.subject = sub;
this.body = bod;
mprogress = new ProgressDialog(activity);
mprogress.setMessage("Sending...");
}
@Override
protected String doInBackground(Void... voids) {
try {
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
private String getDataFromApi() throws IOException {
// getting Values for to Address, from Address, Subject and Body
String user = "me";
String to = "jalalhilal0@gmail.com";
String from = mCredential.getSelectedAccountName();
MimeMessage mimeMessage;
String response = "";
try {
mimeMessage = createEmail(to, from, subject, body);
response = sendMessage(mService, user, mimeMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
return response;
}
// Method to send email
private String sendMessage(Gmail service,
String userId,
MimeMessage email)
throws MessagingException, IOException {
Message message = createMessageWithEmail(email);
// GMail's official method to send email with oauth2.0
message = service.users().messages().send(userId, message).execute();
System.out.println("Message id: " + message.getId());
System.out.println(message.toPrettyString());
return message.getId();
}
// Method to create email Params
private MimeMessage createEmail(String to,
String from,
String subject,
String bodyText) throws MessagingException {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
DataHandler handler = new DataHandler(new ByteArrayDataSource(bodyText.getBytes(), "text/plain"));
InternetAddress tAddress = new InternetAddress(to);
InternetAddress fAddress = new InternetAddress(from);
email.setFrom(fAddress);
email.addRecipient(javax.mail.Message.RecipientType.TO, tAddress);
email.setSubject(subject);
email.setDataHandler(handler);
email.setSentDate(new Date());
// Create Multipart object and add MimeBodyPart objects to this object
Multipart multipart = new MimeMultipart();
// Changed for adding attachment and text
// email.setText(bodyText);
BodyPart textBody = new MimeBodyPart();
textBody.setText(bodyText);
multipart.addBodyPart(textBody);
email.setContent(multipart);
return email;
}
private Message createMessageWithEmail(MimeMessage email)
throws MessagingException, IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
return message;
}
@Override
protected void onPreExecute() {
mprogress.show();
}
@Override
protected void onPostExecute(String output) {
mprogress.hide();
/*if (output == null || output.length() == 0) {
showMessage(view, "No results returned.");
} else {*/
}
/*@Override
protected void onCancelled() {
mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
Utils.REQUEST_AUTHORIZATION);
} else {
showMessage(view, "The following error occurred:\n" + mLastError);
Log.v("Error", mLastError + "");
}
} else {
showMessage(view, "Request Cancelled.");
}
}*/
}
在mainactivity中,我使用此类(GmailSend)发送这样的电子邮件:
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.gmail.GmailScopes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link ZDDFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link ZDDFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class ZDDFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
private InternetDetector internetDetector;
private Spinner spinner;
private TimePicker timePicker;
private EditText editmarche;
private FloatingActionButton fabsend;
private Context ctxtest;
private GoogleSignInAccount acct;
private GoogleAccountCredential accountCredential;
private static final String[] SCOPES = {
GmailScopes.GMAIL_LABELS,
GmailScopes.GMAIL_COMPOSE,
GmailScopes.GMAIL_INSERT,
GmailScopes.GMAIL_MODIFY,
GmailScopes.GMAIL_READONLY,
GmailScopes.MAIL_GOOGLE_COM
};
public ZDDFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ZDDFragment.
*/
// TODO: Rename and change types and number of parameters
public static ZDDFragment newInstance(String param1, String param2) {
ZDDFragment fragment = new ZDDFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View v = inflater.inflate(R.layout.fragment_zdd, container, false);
ctxtest = getContext();
internetDetector = new InternetDetector(ctxtest);
acct = GoogleSignIn.getLastSignedInAccount(this.getContext());
accountCredential = GoogleAccountCredential.usingOAuth2(
getContext(), Arrays.asList(SCOPES))
.setSelectedAccountName(acct.getAccount().name)
.setBackOff(new ExponentialBackOff());
List exempleList = new ArrayList();
exempleList.add("Aucun");
exempleList.add("Formation tardive du train");
exempleList.add("Régulation");
exempleList.add("Panne machine");
exempleList.add("Engagement chantier tardif");
exempleList.add("Chantier rendu en retard");
exempleList.add("Autres");
ArrayAdapter adapter = new ArrayAdapter(
getContext(),
android.R.layout.simple_spinner_item,
exempleList
);
timePicker = v.findViewById(R.id.timezd);
timePicker.setIs24HourView(true);
//Floating invisible avec le keyboard
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
editmarche = v.findViewById(R.id.editmarched);
editmarche.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editmarche.getWindowToken(), 0);
editmarche.setFocusable(false);
editmarche.setFocusableInTouchMode(true);
editmarche.setCursorVisible(false);
return true;
} else
return false;
}
});
fabsend = v.findViewById(R.id.fab_zd);
fabsend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!internetDetector.checkMobileInternetConn()) {
showMessage(getView(), "Pas de connexion Internet");
} else
getResultsFromApi2(v);
Fragment fragment = new ZDDFragment();
if (fragment != null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.mainFrame, fragment);
ft.commit();
}
}
});
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner = v.findViewById(R.id.spinner_zd_d);
spinner.setAdapter(adapter);
return v;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
private boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(getContext());
return connectionStatusCode == ConnectionResult.SUCCESS;
}
private void acquireGooglePlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(getContext());
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
}
}
void showGooglePlayServicesAvailabilityErrorDialog(final int connectionStatusCode) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
Dialog dialog = apiAvailability.getErrorDialog(
getActivity(),
connectionStatusCode,
Utils.REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
private void getResultsFromApi2(View view) {
if (!isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} /*else if (!internetDetector.checkMobileInternetConn()) {
showMessage(view, "Pas de connection Internet...");
} */ else {
new MyTask();
showMessage(getView(), "Message envoyé avec succés");
}
}
private void showMessage(View view, String message) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
}
private class MyTask extends AsyncTask<Void, Void, String> {
//used for database conection purpose
String html = "Numéro de marche : " + editmarche.getText().toString() + "\nRetard (+5min) : " + spinner.getSelectedItem().toString() + "\nHeure : " + timePicker.getHour() + ":" + timePicker.getMinute();
MyTask() {
new GmailSend(getActivity(), accountCredential, ctxtest, "Zone Dense - Départ", html).execute();
}
// use the Cursor returned from the doInBackground method
@Override
protected String doInBackground(Void... voids) {
new MyTask();
return null;
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(String output) {
if (MyTask.this.getStatus() == Status.FINISHED) {
showMessage(getView().findViewById(android.R.id.content), "Message envoyé avec succés");
}
}
}
}
针对GoogleAuthUtil的编辑查找解决方案:对于具有相同错误的人,只需添加以下代码,问题就不在GmailSend或Myactivity中,而是我使用GoogleSigninOptions时的登录活动(查看handleSignInResult,GoogleTokenResponse)>
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
private FloatingActionButton signin;
private FloatingActionButton signout;
private GoogleSignInClient mGoogleSignInClient;
private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;
private String[] permissions = {"android.permission.ACCESS_NETWORK_STATE",
"android.permission.CALL_PHONE",
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.READ_PHONE_STATE",
"android.permission.SYSTEM_ALERT_WINDOW",
"android.permission.CAMERA",
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.GET_ACCOUNTS"};
private ProgressDialog mprogress;
private InternetDetector internetDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
int requestCode = 200;
requestPermissions(permissions, requestCode);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
internetDetector = new InternetDetector(getApplicationContext());
signin = findViewById(R.id.signin);
signout = findViewById(R.id.signout);
signin.setImageResource(R.drawable.ic_lock_outline_black_24dp);
signin.setOnClickListener(this);
signout.setOnClickListener(this);
String serverClientId = getString(R.string.server_client_id);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestServerAuthCode(serverClientId)
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
if (GoogleSignIn.getLastSignedInAccount(this) != null)
if (internetDetector.checkMobileInternetConn())
signIn();
else
showMessage(findViewById(android.R.id.content),"Pas de connection internet");
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.signin:
if (internetDetector.checkMobileInternetConn())
signIn();
else
showMessage(findViewById(android.R.id.content),"Pas de connection internet");
break;
case R.id.signout:
signOut();
break;
}
}
@Override
public void onStart() {
super.onStart();
// [START on_start_sign_in]
// Check for existing Google Sign In account, if the user is already signed in
// the GoogleSignInAccount will be non-null.
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
updateUI(account);
// [END on_start_sign_in]
}
private void signIn() {
mprogress = ProgressDialog.show(this,
"Connexion", "Veuillez patientez...", true);
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
private void signOut() {
mGoogleSignInClient.signOut()
.addOnCompleteListener(this, new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// [START_EXCLUDE]
updateUI(null);
// [END_EXCLUDE]
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
handleSignInResult(task);
}
}
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
String authCode = account.getServerAuthCode();
// Exchange auth code for access token
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
"enter client_id",
"enter_client_secret",
authCode, "") // Specify the same redirect URI that you use with your web
// app. If you don't have a web version of your app, you can
// specify an empty string.
.execute();
String test = "*******";
String test1 = "******@gmail\\.com";
String test2 = account.getEmail();
String test3 = "*****@gmail\\.com";
// Signed in successfully, show authenticated UI.
if (test2.matches(test) || test2.matches(test1) || test2.matches(test3)) {
startActivity(new Intent(LoginActivity.this, DrawerActivity.class));
}
// Signed in successfully, show authenticated UI.
signout.setVisibility(View.GONE);
signin.setImageResource(R.drawable.ic_lock_open_black_24dp);
mprogress.dismiss();
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
updateUI(null);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void updateUI(@Nullable GoogleSignInAccount account) {
if (account != null) {
signout.setVisibility(View.VISIBLE);
} else {
signout.setVisibility(View.GONE);
}
}
private void showMessage(View view, String message) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
}
}