Android Scheme Link示例
這部分內(nèi)容是2020-12-09號(hào)新加的內(nèi)容悼泌,這邊主要是彌補(bǔ)以前寫的博客“Android intent-filter的匹配規(guī)則”個(gè)人認(rèn)為缺失的非常重要的通過Scheme Link打開應(yīng)用的示例代碼。以前的內(nèi)容非常繁瑣,實(shí)用性并不是很強(qiáng),不過也說了很多關(guān)于顯示調(diào)用和隱式調(diào)用的東西,想了解Android intent-filter data action category的一些規(guī)則還是值得參考。
這部分是非常常用的一個(gè)需求硝烂,就是用鏈接打開app傳參,或者其他app打開應(yīng)用傳參铜幽。
需要打開的App應(yīng)用設(shè)置:
<activity
android:name="com.axe.SplashActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<data android:scheme="axe" android:host="axeChen" android:path="/splashActivity" android:port="8888"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
這里將要打開一個(gè)應(yīng)用的SplashActivity滞谢,這里配置了data
<data android:scheme="axe" android:host="axeChen" android:path="/splashActivity" android:port="8888"/>
那么scheme就是:axe://axeChen:8888/splashActivity
如果要帶參數(shù)的話:axe://axeChen:8888/splashActivity?appName='myApp'
這里的參數(shù)是appName,值為myApp
- 鏈接調(diào)起:
<a>axe://axeChen:8888/splashActivity?appName='myApp'</a>
- App調(diào)起:
var intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("axe://axeChen:8888/splashActivity?appName='myApp'")
startActivity(intent)
- 參數(shù)獲取
// 獲取Intent數(shù)據(jù)
var uri: Uri? = intent.data
if (uri != null) {
val url = uri.toString()
var appName: String? = uri.getQueryParameter("appName")
appName?.run {
// 獲取到參數(shù)
}
}else{
// app原來的一些邏輯
}
以上就是示例代碼了除抛。
(以下的內(nèi)容為2016年寫的內(nèi)容)
Android intent-filter data action category的匹配規(guī)則
我們知道有兩種方式來啟動(dòng)Activity狮杨,顯示調(diào)用和隱式調(diào)用。當(dāng)使用隱式調(diào)用時(shí)到忽,又會(huì)涉及到IntentFilter的匹配規(guī)則橄教。我確信大多數(shù)開發(fā)者很少關(guān)注隱式調(diào)用,因?yàn)槠綍r(shí)開發(fā)中用到大多數(shù)是顯示調(diào)用喘漏。例如:用Intent直接打開一個(gè)Activity护蝶,或者用Intent通過包名等其他信息打開另外一個(gè)應(yīng)用等。而隱式調(diào)用則使用的比較少翩迈,當(dāng)然也不是完全不使用滓走。例如:當(dāng)我們需要打開瀏覽器訪問某個(gè)鏈接時(shí),手機(jī)上可能存在多個(gè)瀏覽器帽馋,我們也無法拿到某一個(gè)瀏覽器的包名搅方,那么一般情況下我們會(huì)寫如下代碼:
Intent intent = new Intent();
intent.setAction("android.intent.action.View");
intent.setDate(Uri.parser("鏈接地址"));
startActivity(intent);
執(zhí)行完這段代碼后,系統(tǒng)將會(huì)彈框提示選擇哪個(gè)瀏覽器打開绽族。只要這個(gè)Intent中的action(通過setAction()方法配置)能和Activity配置的過濾規(guī)則中的任何一個(gè)action相同即可匹配成功(這里后面會(huì)詳細(xì)分析)姨涡。這里就說明Intent中action匹配到了多個(gè)Activity,所以系統(tǒng)會(huì)將所有能打開這個(gè)鏈接的應(yīng)用展示出來供用戶選擇吧慢。這種通過action匹配activity的方式就是一種典型的隱式調(diào)用涛漂。
首先我們先分析顯示調(diào)用和隱式調(diào)用的原理:
1、Activity的調(diào)用模式
a检诗、顯示調(diào)用
顯示調(diào)用需要明確的指出被啟動(dòng)的對(duì)象的組件信息匈仗、包括包名和類名
示例1:通過包名打開一個(gè)應(yīng)用
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName("com.mg.axe.testappa","com.mg.axe.testappa.MainActivity");
intent.setComponent(cn);startActivity(intent);
示例2: 打開一個(gè)Activity
Intent intent = new Intent(ActivityA.this,ActivityB.class);
startActivity(intent);
(這種方式從嚴(yán)格上講不算顯示調(diào)用,因?yàn)轱@示調(diào)用的意義是 :需要明確的指出被啟動(dòng)的對(duì)象的組件信息,包括包名和類名,這里并沒有指出包名 逢慌。)
b悠轩、隱式調(diào)用
需要Intent能匹配目標(biāo)組件的IntentFilter中所設(shè)置的過濾信息.如果不匹配將無法啟動(dòng)目標(biāo)Activity
示例1:通過action方式匹配對(duì)應(yīng)的Activity
Intent intent = new Intent();
intent.setAction("android.intent.action.View");
startActivity(intent);
運(yùn)行結(jié)果會(huì)像這樣:
為什么會(huì)匹配到這么多應(yīng)用的Activity? 因?yàn)樵谶@些Activity的IntentFilter匹配規(guī)則中有如下規(guī)則:
(由于我們這里沒有匹配其他的條件攻泼,所以會(huì)匹配到很多應(yīng)用的Activity火架,我們可以添加其他的匹配條件,比如入“category”忙菠,“data”的匹配來更加精確的匹配到所需要的Activity)
通過上面的實(shí)例何鸡,大概了解了顯示調(diào)用和隱式調(diào)用的方式。接下來我們將重點(diǎn)放在隱式調(diào)用的IntentFilter的匹配中牛欢。
2.Action的匹配規(guī)則
Intent中的Action必須能夠和Activity過濾規(guī)則中的Action匹配.(這里的匹配是完全相等). 一個(gè)過濾規(guī)則中有多個(gè)action,那么只要Intent中的action能夠和Activity過濾規(guī)則中的任何一個(gè)action相同即可匹配成功骡男。*
在AndroidManifest中添加AActivity的action的匹配規(guī)則<action android:name="com.axe.mg.what" />
<activity
android:name=".AActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<category android:name = "android.intent.category.DEFAULT" />
<action android:name="com.axe.mg.what" />
</intent-filter>
</activity>
然后調(diào)用以下方法即可匹配到AActivity:
public void match(){
Intent intent = new Intent();
intent.setAction("com.axe.mg.what");
startActivity(intent);
}
注意:
1、系統(tǒng)定義了一些Action傍睹。當(dāng)然我們也可以自己定義action隔盛。比如<action android:name="com.axe.mg.what" />
2、在Activity中定義的Action匹配規(guī)則可能有多個(gè)焰望,只要Intent中的action能夠和Activity過濾規(guī)則中的任何一個(gè)action相同即可匹配成功骚亿。例如:
<activity
android:name=".AActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<category android:name = "android.intent.category.DEFAULT" />
<action android:name="com.axe.mg.what" />
<action android:name="com.axe.mg.how"/>
</intent-filter>
</activity>
public void match() {
Intent intent = new Intent();
//只設(shè)置一個(gè)action。依舊能夠成功熊赖。
intent.setAction("com.axe.mg.what");
startActivity(intent);
}
3.category的匹配規(guī)則
如果Intent中的存在category那么所有的category都必須和Activity過濾規(guī)則中的category相同来屠。才能和這個(gè)Activity匹配。Intent中的category數(shù)量可能少于Activity中配置的category數(shù)量震鹉,但是Intent中的這category必須和Activity中配置的category相同才能匹配俱笛。
我們?cè)贏ctivity中配置category匹配規(guī)則:
<activity
android:name=".AActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<category android:name = "android.intent.category.DEFAULT" />
<category android:name="aaa.bb.cc"/>
<action android:name="com.axe.mg.what" />
</intent-filter>
</activity>
運(yùn)行以下代碼可以匹配到AActivity:
public void match(){
Intent intent = new Intent();
intent.addCategory("aaa.bb.cc");
intent.setAction("com.axe.mg.what");
startActivity(intent);
}
注意:1、只通過category匹配是無法匹配到AActivity的传趾。因?yàn)閏ategory屬性是一個(gè)執(zhí)行Action的附加信息迎膜。
所以只靠category是無法匹配的。像如下代碼:
//沒有setAction()無法匹配
public void match(){
Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory("aaa.bb.cc");
startActivity(intent);
}
4.data的匹配規(guī)則
類似于action匹配浆兰,但是data有更復(fù)雜的結(jié)構(gòu)
a.data的結(jié)構(gòu)
<data android:scheme="axe"
android:host="axe"
android:port="axe"
android:path="axe"
android:pathPattern="axe"
android:pathPrefix="axe"
android:mimeType="axe"/>
data 由兩部分組成
mineType 和 URI
mineType: 指媒體類型 例如: image/jpeg vided/* ...
URl 可配置更多信息磕仅,類似于url珊豹。我們可以看下URI的結(jié)構(gòu)
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
content://com.axe.mg:100/fold/subfolder/etc
http://www.axe.com:500/profile/info
我們看下URL的屬性:
Scheme:URI的模式。如果URI中沒有指定Scheme.那么整個(gè)URI無效榕订。默認(rèn)值為content 和 file店茶。
Host:URI的host。比如www.axe.com劫恒。如果指定了scheme和port贩幻,path等其他參數(shù),但是host未指定两嘴,那么整個(gè)URI無效丛楚;如果只指定了scheme,沒有指定host和其他參數(shù)憔辫,URI是有效的趣些。可以這樣理解:一個(gè)完整的URI :http://www.axe.com:500/profile/info 我將后面的prot 和path“:500/profile/info ”去掉,這個(gè)URI任然有效螺垢。如果我單獨(dú)將www.axe.com 那這個(gè)URI就無效了喧务。
Port:URI端口,當(dāng)URI指定了scheme 和 host 參數(shù)時(shí)port參數(shù)才有意義枉圃。
path:用來匹配完整的路徑功茴,如:http://example.com/blog/abc.html,這里將 path 設(shè)置為 /blog/abc.html 才能夠進(jìn)行匹配孽亲;
pathPrefix: 用來匹配路徑的開頭部分坎穿,拿上面的 Uri 來說,這里將 pathPrefix 設(shè)置為 /blog 就能進(jìn)行匹配了返劲;
pathPattern: 用表達(dá)式來匹配整個(gè)路徑玲昧。
b.一些實(shí)例
(1)只匹配scheme
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="test" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="axe" />
</intent-filter>
</activity>
</application>
匹配該Activity只需要data中scheme為axe就能匹配到
public void match(){
Intent intent=new Intent();
//只設(shè)置Intent的Data屬性
intent.setData(Uri.parse("axe://haha"));
startActivity(intent);
}
(2)匹配 scheme host port
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="test" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.axe.com"
android:port="8888"
android:scheme="axe" />
</intent-filter>
</activity>
匹配這個(gè)Activity需要 scheme 為 axe ,host 為 www.axe.com篮绿, port為8888才能匹配孵延。 只要有一個(gè)不正確都無法匹配
public void match(View view){
Intent intent=new Intent();
//只設(shè)置Intent的Data屬性
intent.setData(Uri.parse("axe://www.axe.com:8888/mypath"));
startActivity(intent);
}
(3)匹配 scheme host path
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.axe.com"
android:path="/mypath"
android:scheme="axe" />
</intent-filter>
</activity>
匹配這個(gè)Activity 必須 scheme為 axe, host 為 www.axe.com亲配, path 為 mypath
才能匹配
public void match(View view) {
Intent intent = new Intent();
intent.setData(Uri.parse("axe://www.axe.com:4545/mypath"));
//port不寫任然能匹配. data中沒有要求做匹配
//intent.setData(Uri.parse("axe://www.axe.com/mypath"));
startActivity(intent);
}
(4) 匹配 scheme host port path
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axe" />
</intent-filter>
</activity>
匹配這個(gè)Activity 必須 scheme為 axe,尘应,host 為 www.axe.com, path 為 mypath吼虎,
port 為8888 才能匹配
public void match(V) {
Intent intent = new Intent();
intent.setData(Uri.parse("axe://www.axe.com:8888/mypath"));
startActivity(intent);
}
(5)mintype匹配
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="axe/abc"
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axe" />
</intent-filter>
</activity>
可以看到我們添加了mimeType犬钢。這種匹配方法我們需要做改變。我們不能使用
setType 和 setData 思灰, 需要使用setDataAndType()玷犹。
從源碼可以看出:setType() 會(huì)將URL設(shè)為null; setData()會(huì)將mineType設(shè)為null洒疚;以下為源碼:
public Intent setType(String type) {
mData = null;
mType = type;
return this;
}
public Intent setData(Uri data) {
mData = data;
mType = null;
return this;
}
匹配這個(gè)Activity 必須 scheme為 axe歹颓, host 為 www.axe.com坯屿, path 為 mypath,
port 為8888晴股, mineType 為 axe/abc才能匹配愿伴。
public void match() {
Intent intent = new Intent();
//注意這個(gè)方法
intent.setDataAndType(Uri.parse("axe://www.axe.com:8888/mypath"),"axe/abc");
startActivity(intent);
}
(6)Scheme的默認(rèn)值content 和 file。
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
上面的配置中我們并沒有指定scheme电湘。我們可以通過默認(rèn)值content 和 file匹配。
public void match(){
Intent intent=new Intent();
//content也可匹配
intent.setDataAndType(Uri.parse("file://axe"),"image/png");
startActivity(intent);
}
(7)存在多個(gè)data的匹配
一個(gè)Activity只要能匹配任何一組data,并且每個(gè)data都指定了完整的屬性(有時(shí)候匹配不上, 這個(gè)規(guī)律還未找到)
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 只要Intent的Data屬性的scheme是lee鹅经,即可啟動(dòng)該Activity -->
<data
android:mimeType="axe/abc"
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axe" />
<data
android:mimeType="axe/ddd"
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axee" />
</intent-filter>
</activity>
以下兩種方式都可以匹配.但是有時(shí)候會(huì)匹配不到.暫時(shí)不知道規(guī)律.建議只使用一個(gè)data.如果有多個(gè)規(guī)則需要匹配. 那就添加intent-filter
public void match() {
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("axe://www.axe.com:8888/mypath"),"axe/abc");
startActivity(intent);
}
public void match() {
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("axee://www.axe.com:8888/mypath"),"axe/ddd");
startActivity(intent);
}
4.其他的技巧
a.無法匹配時(shí)的crash log
//類似于這樣寂呛。
Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { cat=[android.intent.category.DEFAULT,aaa.bb.cc] }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1781)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1501)
at android.app.Activity.startActivityForResult(Activity.java:3804)
at android.app.Activity.startActivityForResult(Activity.java:3765)
b.一個(gè)Activity只要能匹配任何一組intent-filter,即可成功啟動(dòng)對(duì)應(yīng)的Activity
<activity
android:name=".CActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="axe/abc"
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axe" />
</intent-filter>
<intent-filter>
<action android:name="xx" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="axe/ddd"
android:host="www.axe.com"
android:path="/mypath"
android:port="8888"
android:scheme="axee" />
</intent-filter>
</activity>
以下兩種方式都可以匹配
public void match() {
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("axe://www.axe.com:8888/mypath"),"axe/abc");
startActivity(intent);
}
public void match() {
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("axee://www.axe.com:8888/mypath"),"axe/ddd");
startActivity(intent);
}
有參考來自:
http://www.cnblogs.com/wolipengbo/p/3427574.html
http://blog.csdn.net/eyishion/article/details/51113094
非常感謝你們的blog瘾晃!給我很大的幫助贷痪。