Android開發--調用系統郵件

Android系統的開源性使其在當前智能手機市場佔據絕對優勢,同時也產生了各種各樣的機型和系統。這使得我們Android開發人員需要根據不同的機型和系統去做對應的適配。

正文

本篇所述需求爲調用本地郵件客戶端發送帶有附件的郵件。

第一種常規調用郵件

 

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setData(Uri.parse("mailto:"));
intent.putExtra(Intent.EXTRA_EMAIL, "");
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
startActivity(Intent.createChooser(intent, "分享一下"));

加載效果如下:

ACTION_SEND.png

我們看到第一種情況,我們標識的郵件(mailto),但是實際執行卻成了分享文件,雖然其中也有郵件客戶端,但是卻增加了用戶的操作步驟,這樣的情況是產品經理不可接受的,所以我們嘗試第二種方法。

第二種使用SENDTO來試試(網上多提倡此種方式)

 

  Intent intent = new Intent(Intent.ACTION_SENDTO);
  intent.setData(Uri.parse("mailto:"));
  intent.putExtra(Intent.EXTRA_EMAIL, "");
  intent.setType("text/plain");
  intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
  startActivity(Intent.createChooser(intent, "分享一下"));

SENDTO代碼加載如下:

ACTION_SENDTO.png

SENDTO確實能調用郵箱客戶端,但是上面的截圖是“沒有應用可執行此操作”。爲什麼說確實能調用呢,因爲在有的機型上確實可以調用,但是華爲平板卻沒有調起來。我們是不是就可以推測華爲把Android系統郵箱相關標識改了呢?有興趣的同學可以去看看華爲系統的源碼。既然這樣的方式不行,那麼我們就繼續探索還有沒有其他的方法。

第三種方式SEND_MULTIPLE多附件發送

SENDTO是發送單個附件,而SEND_MULTIPLE卻是攜帶多個附件進行發送,下面我們來試試這一段代碼執行的情況

 

Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setData(Uri.parse("mailto:"));
intent.putExtra(Intent.EXTRA_EMAIL, "");
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, list);//Uri.fromFile(file)
startActivity(Intent.createChooser(intent, "分享一下"));

多附件執行截圖如下:

ACTION_SEND_MULTIPLE.png

我們看到這個多附件的發送同第一種情況類似,調起了系統的所有郵件客戶端和藍牙,不過我們不需要調用這麼多應用,那麼我們就再試試其他的方式。

第四種直接調用應用

相信肯定有直接能夠調用某個工具軟件的方式,我們直接用這種方式會不會能夠達到我們想要的效果呢?我們一起來試試

 

 Intent intent = new Intent(android.content.Intent.ACTION_SEND);
 intent.putExtra(Intent.EXTRA_EMAIL, "");
 intent.setType("text/plain");
 intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
 intent.setClassName("com.android.email","com.android.email.activity.MessageCompose");
 startActivity(Intent.createChooser(intent, "分享一下"));

直接調用執行效果截圖:

最終效果圖.png

這樣看我們是不是找幾個不同型號不同系統的手機,獲取對應的包名和Activity就可以達到我們想要的效果呢?答案是肯定的。並且經過試用小米、紅米、三星、華爲、榮耀、努比亞,發現可以實現需求。因爲手上沒有魅族的機器所以還沒有在魅族的系統上嘗試過,有條件的同學可以試試,順便告知一下。我將萬分感謝。

最終代碼

奉上最終代碼,因爲一個類就可以解決了,就不在放Github了。

 

package com.hewc.sendmail;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.StrictMode;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.io.File;

public class MainActivity extends AppCompatActivity {

private Context context;
private String filePath = "/storage/emulated/0/20.txt";

private static final String[] NARMAL_PHONE = {"com.android.email", "com.android.email.activity.MessageCompose"};
private static final String[] MIUI_PHONE = {"com.android.email", "com.kingsoft.mail.compose.ComposeActivity"};
private static final String[] SAMSUNG_PHONE = {"com.samsung.android.email.provider", "com.samsung.android.email.composer.activity.MessageCompose"};


@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    setContentView(R.layout.activity_main);
    // android 7.0系統解決拍照的問題
    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());
    builder.detectFileUriExposure();

    TextView tv = findViewById(R.id.tv);
    tv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            File file = new File(filePath);
            try {
                Intent intent = new Intent(android.content.Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_EMAIL, "");
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
                if (getDeviceBrand().toUpperCase().contains("HONOR") || getDeviceBrand().toUpperCase().contains("HUAWEI") || getDeviceBrand().toUpperCase().contains("NUBIA")) {
                    intent.setClassName(NARMAL_PHONE[0], NARMAL_PHONE[1]);
                } else if (getDeviceBrand().toUpperCase().contains("XIAOMI") || getDeviceBrand().toUpperCase().contains("XIAOMI")) {
                    intent.setClassName(MIUI_PHONE[0], MIUI_PHONE[1]);
                } else if (getDeviceBrand().toUpperCase().contains("SAMSUNG")) {
                    intent.setClassName(SAMSUNG_PHONE[0], SAMSUNG_PHONE[1]);
                }
                startActivity(Intent.createChooser(intent, "分享一下"));
            } catch (Exception e) {
                e.printStackTrace();
                Intent intent = new Intent(Intent.ACTION_SEND);
                intent.setData(Uri.parse("mailto:"));
                intent.putExtra(Intent.EXTRA_EMAIL, "");
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
                startActivity(Intent.createChooser(intent, "分享一下"));
            }

        }
    });
}

  /**
   * 獲取手機廠商
   *
   * @return 手機廠商
   */
  public static String getDeviceBrand() {
      Log.e("--獲取手機廠商--:", android.os.Build.BRAND);
      return android.os.Build.BRAND;
  }
}

關於獲取第三方應用Activity名稱的方法:
adb shell dumpsys activity | findstr "mFocusedActivity" (Windows系統下)

 

延伸

adb shell dumpsys activity---------------查看ActvityManagerService 所有信息
adb shell dumpsys activity activities----------查看Activity組件信息
adb shell dumpsys activity services-----------查看Service組件信息
adb shell dumpsys activity providers----------產看ContentProvider組件信息
adb shell dumpsys activity broadcasts--------查看BraodcastReceiver信息
adb shell dumpsys activity intents--------------查看Intent信息
adb shell dumpsys activity processes---------查看進程信息

通過adb shell命令查看當前與用戶交互的activity

在做android逆向的時候,有時候會需要知道當前的界面處於哪個Activity,這時候就可以使用adb shell命令來查看當前與用戶交互的Activity名稱。先給出原文地址:

http://stackoverflow.com/questions/11549366/print-the-current-back-stack-in-the-log/26424943#26424943

有如下幾種方法可以獲取:

方法一:

adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'

查詢結果爲:

其中TaskRecord即爲查詢到的記錄。其中com.sina.weibo爲包名,.VisitorMainTabActivity爲對應的Activity名稱。

方法二:

adb shell dumpsys activity | grep -i run

查詢結果爲:

方法三:

adb shell dumpsys activity | grep "mFoc"

查詢結果爲:


其中mFocusedActivity就是當前和用戶交互的Activity。

如果在Windows下使用時,則先通過adb shell進入到adb shell裏,然後把adb shell去了,再將餘下的複製到$後面進行執行,例如:

這樣就不會提示:“grep”不是內部或外部命令,也不是可運行查詢了

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章