1. 程式人生 > >如何進入系統撥號盤,或者直接打電話,發簡訊,還有data,scheme,uri的關係

如何進入系統撥號盤,或者直接打電話,發簡訊,還有data,scheme,uri的關係

一.背景

Android做app,有時候需要去呼叫系統的撥號盤,或者直接撥打某個電話,還有傳送簡訊(直接傳送和帶著預設的號碼和內容跳到系統應用),網上有很多例子,可以直接拿來用,可是如果換做是呼叫其他的系統應用你會咩?

下面就授之以漁!!!

二.例項

用一個跳到簡訊的需求來講怎麼查原始碼(點我獲取應用層程式碼)。

(1)首先用模擬器開啟新建簡訊,觀察開啟了什麼Activity

          

(2)從上面可以發現啟動了ComposeMessageActivity,接下來檢視他的原始碼和Intent-filter


(3)檢視


通過上面就可以知道怎麼跳到資訊應用,很多會對 Data,MineType還有Scheme搞不清,等會我就區分下,先講完這裡,如果要帶著內容怎麼搞?

(4)看看怎麼帶著內容跳到系統的資訊應用


所以綜上基本就可以知道怎麼用了

(5)程式碼

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btDialDirect;
    private Button btDialInDirect;
    private Button btSendSms;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btDialDirect = (Button) findViewById(R.id.bt_dial_direct);
        btDialInDirect = (Button) findViewById(R.id.bt_dial_indirect);
        btSendSms = (Button) findViewById(R.id.bt_sendSms);
        btSendSms.setOnClickListener(this);
        btDialDirect.setOnClickListener(this);
        btDialInDirect.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        Uri data = null;
        if(btDialDirect == v){
            //直接打出去
            intent.setAction(Intent.ACTION_CALL);
            data = Uri.parse("tel:"+110);
        }else if(btDialInDirect == v){
            //跳到撥號盤然後自己打
            intent.setAction(Intent.ACTION_DIAL);
            data = Uri.parse("tel:"+110);
        }else if(btSendSms == v){
            intent.setAction(Intent.ACTION_SENDTO);
            data = Uri.parse("smsto:" + 5556);
            intent.putExtra("sms_body","come here");
        }
        intent.setData(data);
        startActivity(intent);
    }
}
詳細的原始碼就不放了,不能再簡單了。。。

三.講講data,scheme,uri的關係

Activity之間的跳轉分為2種:

       (1)顯式跳轉:

在可以引用到那個類, 並且可以引用到那個類的位元組碼時可以使用。一般用於自己程式的內部。顯式跳轉不可以跳轉到其他程式的頁面中。

       (2) 隱式跳轉:

可以在當前程式跳轉到另一個程式的頁面。隱式跳轉不需要引用到那個類,但是必須得知道那個介面的動作(action)和資訊(category),有時還需要Data

Activity之間通過Intent進行通訊。Intent即意圖,用於描述一個頁面的資訊,同時也是一個數據的載體。

隱式跳轉的Activity(自己寫這個Activity要在清單檔案註冊action,和category,data(有時),

其他app隱式呼叫這個Activity,就不用註冊Activity

因為自己的如果不註冊,那觸發這些action,category都不知道是啟動哪個Activity隱式跳轉可以跳轉到其他程式的Activity只要知道Activity的動作(action)以及資訊(category)。因此,能夠被隱式跳轉的Activity,在清單檔案中宣告時必須指定動作和資訊這兩個屬性。



上面的寫的android.intent.category.DEFAULT可以不寫原因是系統用過startActivity或者startActivityForResult的時候會預設為Intent加上“android.intent.category.Default”這個category

(3)系統入口:

若清單檔案中的Activity宣告為:

則此Activity將作為程式的入口,有幾個作為入口的Activity,apk檔案安裝的時候就會生成幾個圖示。

(4)data,mimeType和URI的區別

<data android:scheme="http" />
                <data android:scheme="https" />
                <data android:scheme="inline" />
                <data android:mimeType="text/html"/>
                <data android:mimeType="text/plain"/>
                <data android:mimeType="application/xhtml+xml"/>
                <data android:mimeType="application/vnd.wap.xhtml+xml"/>
或者
 <data 			android:scheme="http"
                android:scheme="https"
                android:scheme="inline" 
               android:mimeType="text/html"
                android:mimeType="text/plain"
                android:mimeType="application/xhtml+xml"
                android:mimeType="application/vnd.wap.xhtml+xml"/>

可以看出上面的data由兩部分組成mimeType和URI組成

mimeType(媒體型別,比如 image/jpeg,audio/mpeg4-generic 和video)

URI,下面是它的結構<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

實際例子

Content://com.example.project:200/folder/subfolder/etc

Scheme:URI的模式(URI預設值為content和file),比如http,file,content等,如果URI中沒有指定scheme,那麼整個URI的其他引數無效,他也意味著URI是無效的(就像Uri.parse("smsto:" + 5556);如果沒有寫smsto,那後面的5556就沒有什麼軟用

Host:是URI的主機名

Port:URI中的埠號

注意:

<intent-filter>    <data android:mimeType="image/*" />。。。</intent-filter>

意這種規則制定了媒體型別為所有型別的圖片,雖然沒有指定URI,但是卻有預設值,URI預設值為content和file,也就是雖然沒有指定URI,但是Intent中的URI部分的scheme必須為Content或者file才能匹配

intent.setDataAndType(Uri.parse(“file://abc”),”image/png”).(注意setData和setType不能單獨寫否則會互相清空

(5)一些注意事項

Intent-Filter的匹配規則對於Service和BroadCastReceiver也是同樣的道理,不過系統對於service的建議是儘量使用顯示呼叫方式來啟動服務。

但是要注意一點,如果硬是方式開啟一個Activity的時候,需要做一個判斷,看是否有Activity能夠匹配我們的隱式Intent 

判斷是否有匹配的隱式 (避免不匹配直接崩掉)

1.PackManager    resolveActivity

2.Intent    resolveActivity

3.PackMagager   querryIntentActivityes,這個方法和resolveActivity方法不同的是:它不是返回最佳匹配的Activity資訊而是返回所有成功匹配的Activity資訊,我們看一下兩者的原型

Public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags)

Public abstract ResolveInfo resolveActivity (Intent intent ,int flags)

第二個引數要使用 MATCH_DEFAULT_ONLY 這個標記位,這個標記為的含義是僅僅匹配那些在intent-filter中聲明瞭<category android:name = “android.intent.category.Default/>”這個category的Activity

這個標記為的意義在於,只要上述的兩個方法不返回null,那麼startActivity一定可以成功,如果不用這個標記位,就會把intent-filter中category不含Default的那些Activity匹配出來,從而導致導致startActivity可能失敗,因為不含有Default這個category的Activity是無法接收隱式Intent