安卓程序开发入门

发布时间 2023-08-16 17:22:44作者: Aibot

Step1

本步骤主要复习安卓软件开发的基本流程;实验共有四个要求,即编写一个会重启后自启动的位置显示,并具备在子进程中调用住进程UIChange函数功能的,同时能够使用反射方法调用libs库中依赖的jar文件的安卓app。按照实验指导书的要求依次实现上述要求。

1-1后台服务

实现了接收重启命令启动程序、后台更新gps数据、获取前台显示和位置权限等三项核心功能。

思路

  1. 首先编写接收重启广播的代码,即SecretBootReceicer.java文件;通过Toast方法实现调试。
public class SecretBootReceiver extends BroadcastReceiver {
    public SecretBootReceiver(){}
    @Override
    public void onReceive(Context context, Intent intent) {}
  1. 接下来进行主活动页面代码的编写,位置和悬浮显示的权限也在该MainActivity.java文件中申请。

该环节中的``floatingWindow的权限申请方法因为随着安卓系统版本不同,申请方法,颇费了一番周折。并且在技术选型上,也存在系统通知 (Notification) 或者浮动窗口 (FloatingWindow) 来代替 Toast`的问题。最后也是根据就近原则(资料最多原则),选择浮动窗口方案。

另外值得说明的是在实验过程中,申请权限以及注册服务都需要在AndroidManifest.xml文件中进行事先声明,由于缺少这一先验知识,在调试代码的过程中走了一些弯路。当然根据SDK版本判断不同的GPS申请权限方法也是踩了坑之后才发现的。

private ActivityResultLauncher<Intent> floatingWindowLauncher;
startActivityForResult(intent, REQUEST_CODE_FLOATING_WINDOW_PERMISSION);
ActivityCompat.requestPermissions(this,new String[]          {Manifest.permission.ACCESS_FINE_LOCATION},
                    REQUEST_LOCATION);
startService(new Intent(this, SecretService.class));
onRequestPermissionsResult;
onActivityResult;
  1. 最后是获取位置服务并显示的功能,也是本软件的核心逻辑,在SecretService.java文件中。主要包括服务注册函数,后台执行函数,位置获取函数和显示函数。
private Runnable runnable = new Runnable() {
  @Override
  public void run() {
      showLocation();
      handler.postDelayed(this, MIN_TIME_BW_UPDATES);
  }
};
private void getLocation();
private void showLocation();
@Override
public void onLocationChanged(Location location) {}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {}

完成上述的代码逻辑编写之后,根据网络上的提示进行Manifest清单文件的配置就可以完成这个app的1-1后台运行显示位置服务的功能了。

结果

观察是否自启动:无论是adb模拟重启还是重启模拟器均实现了reboot后自启动✅

释放内存是否结束:手动清理内存后,进程被杀死且没有被再次唤醒。✅

image20230628170839681

image20230629202644928

1-2子线程中更新ui

该问题是创建一个子线程进行数据输入输出的处理,同时需要在子线程收到数据后更新住进程的ui。通过在子线程中调用runOnUiThread 方法来实现子线程中更新住线程ui

思路

在app中画出输入输出框,并在MainActivity类中进行按钮行为的绑定。在按钮绑定的行为中,点击后新建一个线程来显示对话框。获取输入框中的内容并据此新建一个对话框,然后利用runOnUiThread在主线程中显示对话框。

mEditText = findViewById(R.id.edit_text);
mButton = findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        final String text = mEditText.getText().toString();

        // 创建一个新的线程来显示对话框
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 在子线程中创建对话框并设置文本内容
                final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("Content");
                builder.setMessage(text);
                // 在主线程中显示对话框
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        builder.show();
                    }
                });
            }
        }).start();
    }
});

结果

1-3反射调用类

通过反射的方法调用calsses.jar文件中的PoRELab类中的变量和方法。采用jd-gui工具查看给定jar文件中的包名,类名,变量名,方法名及其参数方便调用。

方法

下载安装jd-gui后打开classes.jar仔细观察。

jar -tf Step1_Task3_classes.jar| grep 'class' 
java -jar /Users/aibot/Downloads/jd-gui-osx-1.6.6/JD-GUI.app/Contents/Resources/Java/jd-gui-1.6.6-min.jar

之后进行反射调用。

try {
    Class<?> poRELabClass = Class.forName("com.pore.mylibrary.PoRELab", true, getClassLoader());
    // 创建 PoRELab 类的实例
    Object poRELabInstance = poRELabClass.newInstance();
    // 获取 curStr 字段的值
    Field curStrField = poRELabClass.getDeclaredField("curStr");
    curStrField.setAccessible(true);
    String curStrValue = (String) curStrField.get(poRELabInstance);
    // 调用 privateMethod 方法
    Method privateMethod = poRELabClass.getDeclaredMethod("privateMethod", String.class, String.class);
    privateMethod.setAccessible(true);
    privateMethod.invoke(poRELabInstance,"privateMethod","hello");
    Log.d("MainActivity", "curStrValue = " + curStrValue);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException |
         NoSuchFieldException | NoSuchMethodException | InvocationTargetException e) {
    e.printStackTrace();
}

结果

得到实验指导书中的结果:

image20230628230349897

1-4签名打包

思路

按照AS集成开发环境中的build,signed-apks,设置key-store和key

key_store和key的密码都是xjtuosv

结果

打包好的apk包含Step中1-1至1-4的全部要求,命名为lab3-1_Step1_tanghangyun.apk