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名稱。先給出原文地址:
有如下幾種方法可以獲取:
方法一:
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”不是內部或外部命令,也不是可運行查詢了