Bootstrap

安卓逆向之Android-Intent介绍

Intent是各个组件之间交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,而且还能在各组件之间传递数据。Intent一般可用于启动Activity、启动Service、发送广播等场景。Intent有多个构造函数的重载。

显式intent

显式 Intent 明确指定要启动的目标组件的类名。通过显式 Intent,开发者可以直接调用应用程序内的特定 Activity 或服务。主要用于应用程序内部组件之间的调用。比如在一个 Activity 中启动另一个 Activity。

Intent intent = new Intent(MainActivity.class,SecondActivity.class);
intent.putExtra("et1",et1Str);
startActivity(intent);
  • Intent intent = new Intent(...):这行代码创建了一个新的 Intent 对象。Intent 是 Android 中用于不同组件(如 Activity、服务等)之间进行通信的基础类。
  • new Intent(MainActivity.class, SecondActivity.class):这个构造函数的两个参数分别是起始 Activity和目标 Activity。在这个例子中,从 MainActivity 目标是 SecondActivity。这意味着当 Intent 被启动时,应用程序会在 SecondActivity 中打开界面。
  • intent.putExtra("et1", et1Str):这行代码用于将额外的数据放入 Intent 中。在这里,"et1" 是键(key),而 et1Str 是与之关联的值。这种方式允许我们在启动的 SecondActivity 中接收 et1Str 的值,便于在新的界面上使用或显示该数据。
  • startActivity(intent):这行代码调用 startActivity 方法,使用先前创建的 Intent 启动 SecondActivity。执行这一行后,应用程序将离开 MainActivity,并加载 SecondActivity 的界面。

隐式intent

隐式 Intent 不直接指定目标组件,而是通过指定一个动作(Action)和/或数据(Data)来指示系统执行某种操作。系统会根据 Intent 的信息查找可以处理该 Intent 的合适组件。

隐式 Intent 允许多个应用程序响应同一个 Intent。只要有一个组件注册了与 Intent 的动作、类别和数据匹配的 intent-filter,就可以接收到这个 Intent。

java部分

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
  • Intent intent = new Intent(Intent.ACTION_VIEW);:这行代码创建了一个新的 Intent 对象,指定了动作为 ACTION_VIEW
  • intent.setData(Uri.parse("https://www.baidu.com"));:这行代码将 Intent 的数据设置为一个 URI(统一资源标识符),在这个例子中是百度的网页地址 "https://www.baidu.com"。使用 Uri.parse() 方法将字符串转换为 URI 格式,这允许系统知道需要打开什么资源。
  • startActivity(intent);:这行代码使用先前创建的 Intent 启动一个新的 Activity。在这里,它通常会打开一个浏览器或系统的 Web 视图,展示所指定的 URL。

AndroidManifest.xml部分

<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.test.action.VIEW" /> 
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http">
            </intent-filter>
 </activity>
  • <activity android:name=".SecondActivity">:这行代码在 AndroidManifest.xml 文件中声明了一个 Activity,名为 SecondActivity
  • <intent-filter>:这个标签用于定义这个 Activity 能够响应的 intent
  • <action android:name="com.example.test.action.VIEW" />:这行代码定义了一个自定义的动作,com.example.test.action.VIEW,意味着这个 Activity 可以处理带有这个动作的 Intent。
  • <category android:name="android.intent.category.DEFAULT" />:这行代码将意图分类为默认类别,表示这个 Activity 可以处理一些常见的意图。
  • <data android:scheme="http" />:这行代码指定了这个 Activity 处理的数据类型,主要是以 http 开头的 URI。在这里,它明确表示这个 Activity 可以接收以 httphttps 开头的网址。

对比

特点

显式 Intent

隐式 Intent

目标指定法

直接指定目标组件(类名)

不指定目标组件,通过 Action、Data 让系统解析

适用场景

应用内组件间的通信

向系统或其他应用发送请求

安全性

相对更安全,明确调用

相对不安全,需要意图过滤器匹配

注册需求

无需在 Manifest 中注册

需要在 Manifest 中使用 intent-filter 注册

使用示例

new Intent(this, SecondActivity.class)

new Intent(Intent.ACTION_VIEW)

intent接收字符串

Intent intent = getIntent();
String data = intent.getStringExtra("et1");

接收名为et1的参数值

第二个组件返回数据

有两种方式一种式通过startActivityForResult,一种是通过back键

第一种 不按back键

// 在第一个 Activity 中  
Intent intent = new Intent(this, SecondActivity.class);  
startActivityForResult(intent, 1); // 1为请求码,用于标识该请求

使用 startActivityForResult() 方法启动第二个组件(Activity)。这允许第一个组件在第二个组件结束时接收结果。

// 在第二个 Activity 中  
EditText editText = findViewById(R.id.editText);  
String resultData = editText.getText().toString();  

// 处理用户点击的按钮  
Button button = findViewById(R.id.button);  
button.setOnClickListener(v -> {  
    Intent resultIntent = new Intent();  
    resultIntent.putExtra("returnData", resultData); // 返回数据  
    setResult(RESULT_OK, resultIntent); // 设置结果为 OK,并传递数据  
    finish(); // 结束该 Activity  
});

在第二个组件(Activity)中,获取用户输入的数据,并在用户完成操作后使用 setResult() 方法将数据返回给第一个组件,然后调用 finish() 结束该 Activity。

@Override  
protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    super.onActivityResult(requestCode, resultCode, data);  
    if (requestCode == 1) { // 检查请求码  
        if (resultCode == RESULT_OK) { // 检查结果是否 OK  
            String returnData = data.getStringExtra("returnData");  
            // 处理返回的数据  
            Toast.makeText(this, "Received: " + returnData, Toast.LENGTH_SHORT).show();  
        }  
    }  
}

在第一个组件中,重写 onActivityResult() 方法,以接收来自第二个组件的结果。可以通过请求码来识别该结果是来自哪个 Activity。

第二种 按back键

如果用户通过点击 Back 键返回到第一个 Activity,在正常情况下,Back 键会关闭第二个 Activity,而不会返回任何结果。在这种情况下,onActivityResult() 方法将不会被调用,因为没有通过 setResult() 返回结果。如果你希望在用户按 Back 键时处理结果,可以在第二个 Activity 中重写 onBackPressed() 方法,并使用 setResult() 返回数据。

@Override  
public void onBackPressed() {  
    Intent resultIntent = new Intent();  
    resultIntent.putExtra("returnData", "User cancelled"); // 设置返回数据  
    setResult(RESULT_CANCELED, resultIntent); // 设置结果为 CANCELLED  
    super.onBackPressed(); // 调用父类方法,结束该 Activity  
}

那么第一个组件种也要重写onActivityResult来接收传递的值

@Override  
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        super.onActivityResult(requestCode, resultCode, data);  
        if (requestCode == 1) { // 检查请求码  
            if (resultCode == RESULT_OK) { // 检查结果是否 OK  
                String returnData = data.getStringExtra("returnData");  
                // 处理返回的数据  
                Toast.makeText(this, "Received: " + returnData, Toast.LENGTH_SHORT).show();  
            }  
        }  
    }  

仔细观察会发现他们第二个组件都是差不多的,都有以下相同的代码逻辑

Intent resultIntent = new Intent();  
resultIntent.putExtra("returnData", "User cancelled"); // 设置返回数据  
setResult(RESULT_CANCELED, resultIntent); // 设置结果为 CANCELLED  
super.onBackPressed(); // 调用父类方法,结束该 Activity  

但是如果通过按back键来返回的话就多了一个 重写onBackPressed的过程,他是针对用户需要进行back键来返回的逻辑处理,通俗来讲也就是针对用户按下back键这一操作的逻辑处理。

不同场景 使用不同的方式 例如:

  • 如果用户必须完成某项操作后才能返回数据,那么使用 不按back的方式 是更合适的选择。
  • 如果你希望记录用户退出的状态,或者允许用户在不完成输入的情况下返回数据,重写 onBackPressed() 来返回一些适合的默认值是一个很好的选择。
;