Android知识Android开发android成神之路

Android 调用手机浏览器的正确方式

2016-09-28  本文已影响3718人  5c7e9c07cd43

效果1

效果1.png
参考 - 程序亦非猿 - Android 调用手机浏览器的正确方式

代码实现

final Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);、intent.setData(Uri.parse("http://www.baidu.com"));
// 注意此处的判断intent.resolveActivity()可以返回显示该Intent的Activity对应的组件名
// 官方解释 : Name of the component implementing an activity that can display the intent
if (intent.resolveActivity(getPackageManager()) != null) {    
  final ComponentName componentName = intent.resolveActivity(getPackageManager()); 
  // 打印Log   ComponentName到底是什么
  Log.e(TAG, "componentName = " + componentName.getClassName());
  startActivity(Intent.createChooser(intent, "请选择浏览器"));
} else {    
  Toast.makeText(getApplicationContext(), "没有匹配的程序", Toast.LENGTH_SHORT).show();
}

不太严谨的实现方式

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri content_url = Uri.parse(url);
intent.setData(content_url);
startActivity(intent);
这里出现问题的原因有2个:
1. 如果手机没有浏览器 - 程序崩溃。
2. 即便是有浏览器 - 也会使用默认的浏览器打开。我想使用Android的同学都用的是第三方的浏览器吧,都不给用户选择的权利,体验很差。

深入学习

final Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.baidu.com"));
if (intent.resolveActivity(getPackageManager()) != null) {    
  final ComponentName componentName = intent.resolveActivity(getPackageManager());   
  Log.e(TAG, "componentName = " + componentName.getClassName());
} 
Log-ComponentName
ComponentName : 原来是 BrowserActivity !
大家可以查看Android 源码找到这个类,本人能力有限,就不再献丑了!
参考 - SuShine的博客 - Android Browser学习二 BrowserActivity 的初始化 --其他重要模块

效果2

效果2.png

代码实现

// 1.Button注册了点击事件 
mRequstBtn.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        
final Intent intent = new Intent();        
intent.setAction(Intent.ACTION_VIEW);        
intent.setData(Uri.parse("http://www.baidu.com"));        
if (intent.resolveActivity(getPackageManager()) != null) {            
  final ComponentName componentName = intent.resolveActivity(getPackageManager());            
  Log.e(TAG, "componentName = " + componentName.getClassName());            
  startActivity(Intent.createChooser(intent, "请选择浏览器"));       
 } 

// 给需要调起的Activity增加 intent-filter
<intent-filter>    
  <action android:name="android.intent.action.VIEW" />    
  <category android:name="android.intent.category.DEFAULT" />    
  <category android:name="android.intent.category.BROWSABLE" />    
  <data android:scheme="http" />
</intent-filter>
解读:
1. Button 注册了点击事件,打开浏览器访问 http://www.baidu.com,注意这里是Http协议
2. 需要被调起的Activity 注册 <intent-filter>  注意这里的约束scheme 是http协议,如果需要访问的网址是https协议,此处约束应该是scheme=https
字段 解释
action 指定 ACTION_VIEW Intent 操作,以便能够从 Google 搜索中访问该 Intent 过滤器
category 定义了 BROWSABLE 和 DEFAULT 这两种 Intent 的 Activity-BROWSABLE:若要能够从 Web 浏览器执行该 Intent,则必须将其设为 BROWSABLE。如果未设置,点击浏览器中的链接将无法解析到您的应用(在这种情况下,只有当前的移动 Web 浏览器能响应该 URL)。DEFAULT:只有当您希望自己的 Android 应用能够响应任何引用网站中的 HTTP 链接时,才需要设为 DEFAULT。在 Google 搜索结果中使用的 Intent 包含您的应用标识信息,以便将您的应用明确指定为接收方。指向您的网站的其他链接不知道您的应用标识,因此 DEFAULT 类别声明了您的应用可以对隐式 Intent 做出响应。
data Activity 接受的每种 URI 格式都有一个这样的标记。此 <data> 标记必须至少包括 android:scheme 属性。您可以添加额外的属性,以进一步细化 Activity 接受的 URI 类型。例如,您可能有多个接受类似 URI 的 Activity,但其不同之处只是在于路径名。在这种情况下,可以使用 android:path 属性或者其变体(pathPattern 或 pathPrefix)来区分对于不同的 URI 路径,系统应打开哪个 Activity

intent-filter详解

效果3

前提: 本人通过手机默认浏览器及html查看器都可以成功调起本地app


步骤1-打开测试的网页.png
// 网页的源码,很简单
<!DOCTYPE html>
<html lang="en">
  <head>    
    <meta charset="UTF-8">    
    <title>        通过浏览器调起本地App    </title>
  </head>
  <body>
    <a href="cmc://test/name/familyname/?name=Wankaz&family_name=Arale">open app</a>
  </body>
</html>
调起App效果图.png
// AndroidManifest.xml文件中的设置
<intent-filter>    
  <action android:name="android.intent.action.VIEW" />      
  <category android:name="android.intent.category.DEFAULT" />      
  <category android:name="android.intent.category.BROWSABLE" />    
  <data        
    android:host="test"        
    android:path="/name/familyname/"        
    android:scheme="cmc" />
</intent-filter>
//  获取到的数据
// 常量的定义
private final static String NAME = "name";
private final static String LASTNAME = "family_name";
// 解析intent中的数据
Intent intent = getIntent();
if (intent != null) {    
  Uri uri = intent.getData();    
  if (uri != null) {        
    Log.e("uri", uri.toString());        
    if ("cmc".equals(uri.getScheme())) {            
      List<String> list = uri.getPathSegments();            
      if (list != null && list.size() == 2) {                            
        mShowWebContentTv.setText("获取到了浏览器数据,姓=" + uri.getQueryParameter(NAME) + ", 名=" + uri.getQueryParameter(LASTNAME));            
      }        
   } else {       
     Log.e("intent", "uri = null");    
  }
} else {    
  Log.e("intent", "intent = null");
}
// 代码解读
1. Html页面中只有一个超链接,<a href="cmc://test/name/familyname/?name=Wankaz&family_name=Arale">open app</a>
2. 设置 AndroidManifest.xml ,为需要调起的页面设置<intent-filter>,我们发现 <intent-filter>里面设置的<data>中的scale,host,path正好对应超链接中的 cmc://test/name/familyname/;而name=Wankaz&family_name=Arale则是对应的数据。
3. 代码中解析数据- 从html页面中获取到的数据见下图

调起App时,获取到html中的内容如下,该内容被封装到Intent中,并通过 intent.getData()获取(使用Uri表示),我们通过uri.getQueryParameter()获取具体字段的值。


Log-Uri.jpeg

问题

1.当App已启动时,也可以调起app,只是获取不到Intent中的数据。我的大概理解是Android中Activity启动时通过Intent在传递数据,如果我们的Activity已经启动,没有再次获取Intent对象,android:launchMode="singleInstance";这个需要其它同学解答下。
2.为什么我把Activity启动模式设置为android:launchMode="singleInstance"?因为如果我们使用默认的standard模式,会发现被调起的app的Activity运行在浏览器的任务栈中了。这是Activity启动模式对调起App的影响。
3.有什么不足之处,希望大家指正。谢谢

上一篇下一篇

猜你喜欢

热点阅读