鸿蒙next ArkTS 反射调用 横空出世

1,552 阅读6分钟

前言导读

各位同学大家好,最近在研究的鸿蒙的组件化。所以就想研究下反射机制 参考了安卓的里面的一些思路。所以写一个案例,现在分享给大家。废话不多说我们正式开始。

官方说明

ArkTS可以通过动态import的方式实现反射功能,通过类名和方法名调用类中的静态成员函数和实例成员函数

为什么要用反射

我们经常会遇到一个问题 就是需求来回改动 ,今天要,明天不要 ,后又要 这样是不是很痛苦。我们不能改变需求方的想法,我们只能改变我们的自己思路。

  • 把我们开发功能拆分成模块。

例如你现在接了一个Google 登录和 Facebook授权登录,我们是不是可以把这个整个授权模块抽离成一个module 我们只需要用反射调用,这样就不需要导包也可以调用到里面方法。如果现在这个项目需要这个功能 我们只需要把这个module 打包成(Android aar )/(鸿蒙 har或者hap) 然后依赖到主工程里面。如果不需要,我们责不需要这个打包后的 (Android aar /鸿蒙 har或者hap) 我们调用的时候扫描到不存我们调用的类就直接走 catch 即可

安卓的实现逻辑

这里先用安卓的做个示例 后面有arkts 版本的讲解

  • 被调用的方法 openActivity
package com.zcehzgr.hawdmoab;

import android.app.Activity;
import android.util.Log;


/***
 *
 *
 * 创建人:xuqing
 * 创建时间:2025年4月3日17:47:09
 *
 */

public class TestOpenController {

    private static final String TAG = "TpController";

    private static TestOpenController instacne=null;
    public static TestOpenController getInstance(){
        if(instacne==null){
            synchronized (TestOpenController.class){
                if(instacne==null){
                    instacne=new TestOpenController();
                }
            }
        }
        return  instacne;
    }


    /***
     *
     * 打开activity 的方法
     * @param activity
     * @param
     */
    public  void openActivity(Activity activity,int code , String msg){
        Log.e(TAG, "openActivity:code   "+code +"msg -- > "+msg );
    }

}
  • 反射调用

package com.example.myapplication;

import android.app.Activity;
import android.util.Log;

import java.lang.reflect.Method;


public class TestPluginFactory {
    private final String TAG = getClass().toString();
    Class singletonClass;//类
    Object singletonInstence;//单例对象

    private  static TestPluginFactory mInstance;

    private TestPluginFactory() {

    }

    public static TestPluginFactory getInstance(){
        if(mInstance == null){
            mInstance = new TestPluginFactory();
        }
        return mInstance;
    }

    public void initPlugin(){
        try {
            singletonClass = Class.forName("com.zcehzgr.hawdmoab.TestOpenController");
            Log.e(TAG, "initPlugin:singletonClass   "+singletonClass);
            if(null !=singletonClass){
                Method getInstenceMethod = singletonClass.getDeclaredMethod("getInstance");
                singletonInstence = getInstenceMethod.invoke(null);
            }

        }catch (Throwable e){
            Log.e(TAG,"clwuysingletonClass initPlugin e"+e.toString());
        }
    }


    public boolean iClassAndSingletonHave(){
        if (singletonClass == null){
            Log.e(TAG,"clwuysingletonClass null");
            return false;
        }
        if (singletonInstence==null){
            Log.e(TAG," clwuysingletonInstence null");
            return false;
        }
        return true;
    }

    /***
     *
     *
     * 反射去调用我们的 openActivity
     * @param activity
     * @param code
     * @param msg
     *
     */
    public void openTestActivity(Activity activity,int code , String msg){
        Log.e(TAG,"clwuyinit:"+TAG);
        if(!iClassAndSingletonHave()){
            return;
        }
        try {
            Log.e(TAG, "code: "+code );
            Log.e(TAG, "msg: "+msg );
            Method initMethod = singletonClass.getDeclaredMethod("openActivity",Activity.class,int.class,String.class);
            initMethod.invoke(singletonInstence,activity,code,msg);
        }catch (Throwable e){
            Log.e(TAG,"openTp e"+e.toString());
        }
    }

}

初始化我们反射插件类和调用 openTestActivity

package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;

import com.example.namespace.R;

public class MainActivity extends AppCompatActivity {



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TestPluginFactory.getInstance().initPlugin();

        findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                TestPluginFactory.getInstance().openTestActivity(MainActivity.this,0,"测试数据局");
            }
        });
    }
}
  • 查看日志

image.png 我们通过日志可以看到 我们已经用反射调用到我们的 openActivity 方法了。

鸿蒙next arkts 反射实现

  • 创建我们的library

如果不会创建是依赖可以看我之前的文章鸿蒙next 开发三方库重磅来袭

image.png

定义我们需要调用的方法

// harlibrary's src/main/ets/utils/Calc.ets
export class Calc {
  public static staticAdd(a:number, b:number):number {
    let c = a + b;
    console.info('DynamicImport I am harlibrary in staticAdd, %d + %d = %d', a, b, c);
    return c;
  }

  public instanceAdd(a:number, b:number):number {
    let c = a + b;
    console.info('DynamicImport I am harlibrary in instanceAdd, %d + %d = %d', a, b, c);
    return c;
  }
}

export function addHarlibrary(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am harlibrary in addHarlibrary, %d + %d = %d', a, b, c);
  return c;
}
  • 在我们的mylibaray里面的Index.ets里面注册

export { Calc, addHarlibrary } from './src/main/ets/components/Calc'

image.png

然后在我们的 entry 的index里面测试调用


aboutToAppear(): void {

  try{
    // HAP's src/main/ets/pages/Index.ets
    import('mylibrary').then((ns:ESObject) => {
      // ns.Calc.staticAdd(8, 9);  // 调用静态成员函数staticAdd()
      // let calc:ESObject = new ns.Calc();  // 实例化类Calc
      // calc.instanceAdd(10, 11);  // 调用成员函数instanceAdd()
      // ns.addHarlibrary(6, 7);  // 调用全局方法addHarlibrary()

      // 使用类、成员函数和方法的字符串名字进行反射调用
      let className = 'Calc';
      let methodName = 'instanceAdd';
      let staticMethod = 'staticAdd';
      let functionName = 'addHarlibrary';
      ns[className][staticMethod](12, 13);  // 调用静态成员函数staticAdd()
      let calc1:ESObject = new ns[className]();  // 实例化类Calc
      calc1[methodName](14, 15);  // 调用成员函数instanceAdd()
      ns[functionName](16, 17);  // 调用全局方法addHarlibrary()
    });
  }catch (e) {
    console.log("反射调用失败")
  }
  
}

index 完整代码



@Entry
@Component
struct Index {
 @State message: string = 'Hello World';

 aboutToAppear(): void {

   try{
     // HAP's src/main/ets/pages/Index.ets
     import('mylibrary').then((ns:ESObject) => {
       // ns.Calc.staticAdd(8, 9);  // 调用静态成员函数staticAdd()
       // let calc:ESObject = new ns.Calc();  // 实例化类Calc
       // calc.instanceAdd(10, 11);  // 调用成员函数instanceAdd()
       // ns.addHarlibrary(6, 7);  // 调用全局方法addHarlibrary()

       // 使用类、成员函数和方法的字符串名字进行反射调用
       let className = 'Calc';
       let methodName = 'instanceAdd';
       let staticMethod = 'staticAdd';
       let functionName = 'addHarlibrary';
       ns[className][staticMethod](12, 13);  // 调用静态成员函数staticAdd()
       let calc1:ESObject = new ns[className]();  // 实例化类Calc
       calc1[methodName](14, 15);  // 调用成员函数instanceAdd()
       ns[functionName](16, 17);  // 调用全局方法addHarlibrary()
     });
   }catch (e) {
     console.log("反射调用失败")
   }

 }

 build() {
   RelativeContainer() {
     Text(this.message)
       .id('HelloWorld')
       .fontSize($r('app.float.page_text_font_size'))
       .fontWeight(FontWeight.Bold)
       .alignRules({
         center: { anchor: '__container__', align: VerticalAlign.Center },
         middle: { anchor: '__container__', align: HorizontalAlign.Center }
       })
       .onClick(() => {
         this.message = 'Welcome';
       })
   }
   .height('100%')
   .width('100%')
 }
}

image.png 我们通过观察日志 和我们的index 代码我们并没improt 导入 Calc这个类 但是我们通过反射还是成功调用了 Calc 下面的 staticAdd instanceAdd addHarlibrary 三个方法。

最后总结:

有了这种反射调用机制,我们就可以让我们的模块化开发得以实现,我们可以在不同的模块之间使用 反射去调用,当然我们 项目在组装功能的时候 不需要某个功能,只需要把当前模块不打包成har 或者hap即可, 这样就方便去应对需求的不断改变的情况。今天的文章就讲到这里了,有兴趣的同学可以拿老师代码去优化修改, 今天的文章就讲到这里有兴趣的 关注我B站教程 了解更多鸿蒙开发的知识 可以关注坚果派公众号 。 谢谢

课程地址

www.bilibili.com/cheese/play…

项目内容:

  • 1 常用布局组件的学习
  • 2 网络请求工具类封装
  • 3 arkui 生命周期启动流程
  • 4 日志工具类的封装
  • 5 自定义组合组件的封装
  • 6 路由导航跳转的使用
  • 7 本地地数据的缓存 以及缓存工具类的封装
  • 8 欢迎页面的实现
  • 9 登录案例和自动登录效果实现
  • 10 请求网络数据分页上拉加载 下拉刷新的实现
  • 11 list数据懒加载实现
  • 12 webview组件的使用

如果使用更多好用的鸿蒙next三方库

友情链接

harmony-utils 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类,致力于助力开发者迅速构建鸿蒙应用,能够满足各种不同的开发需求。

harmony-dialog 一款极为简单易用的零侵入弹窗,仅需一行代码即可轻松实现,无论在何处都能够轻松弹出。