当前位置:   article > 正文

JS和android原生相互调用,JS传string 无限制调用android 原生工具类_android调用javascript服务

android调用javascript服务

JS在服务器端,可以随时更新。给用户的APP预留一些常用工具类,通过JS 调用android 反射生成对象,进而调用android预留的工具类方法。比如各种uitl
js代码:

      function invoke(){
 JSTest.webapp_invoke("com.android.test2mvvm.Test2_App","test");
            JSTest.webapp_invoke("com.android.test2mvvm.Test2_App","test","good");
             JSTest.webapp_invoke("com.android.test2mvvm.Test2_App","test","good",123456);
        JSTest.webapp_invoke("com.android.test2mvvm.Test2_App","test","false",123456);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

被调用android端代码:

binding.Webview.addJavascriptInterface(new WebApp() {
            @JavascriptInterface
            public void showToast(String msg) {
                Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
            }

            @JavascriptInterface
            public void webapp_invoke(String class_name, String method_name, String string) {
                super.webapp_invoke(class_name, method_name, super.string_to_object(string));
            }

            @JavascriptInterface
            public void webapp_invoke(String class_name, String method_name, String string, String string1) {
                Object[] objects = new Object[]{super.string_to_object(string), super.string_to_object(string1)};
                Loge.e(string+":"+string1);
                super.webapp_invoke(class_name, method_name, objects);
            }

            @JavascriptInterface
            public void webapp_invoke(String class_name, String method_name) {
                Loge.e("测试" + ":" + method_name + ":" + class_name);
                super.webapp_invoke(class_name, method_name);
            }

        }, "JSTest");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

因为JS调用android端 传过来的都是String,所以需要转换一下,android 的转换 代码如下:
因为不是做项目,只是demo测试,只简单的转换了boolean和int,string类型的,其他的大同小异,根据需要补上即可

public Object string_to_object(String string) {
        if (string.equals("true")) {
            return true;
        }
        if (string.equals("false")) {
            return false;
        }
        try {
          Integer integer= Integer.valueOf(string);
          return integer;  //能转换成功,没有Exception 则说明是int,否则为string 
        } catch (Exception exception) {
            return string;
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

根据JS传过来的String 反射生成对象,并调用方法的WebApp类:

public class WebApp {
    public void test() {
    }

    public void test(String string) {

    }

    public void app_invoke(Object object, Method method, Object... args) {
        try {
            method.invoke(object, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public Object app_getObject(String class_name) {
        try {
            Class clazz = Class.forName(class_name);
            Method method = clazz.getDeclaredMethod("getInstance", null);//这里 直接根据getInstance 获取到单例 然后用来调用对象的各个方法
            Loge.e(class_name);
            Object object = method.invoke(null);
            return object;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Method app_getMethod(String class_name, String method_name, Object... objects) {
        try {
            Class clazz = Class.forName(class_name);
            Class[] classes1 = new Class[objects.length];
            for (int i = 0; i < objects.length; i++) {
                Class c = objects[i].getClass();
                classes1[i] = c;
                Loge.e(c.getName());
            }
            Method method = clazz.getMethod(method_name, classes1);

            return method;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object string_to_object(String string) {
        if (string.equals("true")) {
            return true;
        }
        if (string.equals("false")) {
            return false;
        }
        try {
          Integer integer= Integer.valueOf(string);
          return integer;
        } catch (Exception exception) {
            return string;
        }

    }

    public void webapp_invoke(String class_name, String method_name, Object... objects) {
        app_invoke(app_getObject(class_name), app_getMethod(class_name, method_name, objects), objects);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

最终被调用的Test2_App类:

@HiltAndroidApp
public class Test2_App extends Application {
  public static Application context;
  public static Application getInstance() { //尽量每一个工具类都用 getInstance()来获取单例,这样在WebApp反射的时候,可以拿到单例,进而可以调用里面的方法.
        return context;
    }
    public void test(String s) {
        Loge.e("测试一下" + s);
    }

    public void test() {
        Loge.e("测试一下");
    }

    public void test(String s, Integer jj) {
        Loge.e("测试一下" + s + "-" + jj);
    }

    public void test(Boolean b, Integer integer) {
        Loge.e(String.valueOf(b) + integer + "测试测试");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

服务端随时可以更改用户的UI,随时可以增加或者删除一些功能,不可能强求用户三天俩头更新升级的,一些灵活多变的UI尽量用JS实现,只需每次用户登录的时候更新一下即可。而且 android+h5是大势所趋。在后面追加一个使用room的实例,,,使用JS的好处就是灵活多变:

   function getUser(){
        JSTest.webapp_invoke("com.android.test2mvvm.test5.fragment7.dao.AppDatabase","getAllUser");//获取所有用户
        }
        
       var json={"account":"4","introduction":"null","nickname":"null","pwd":"4","uid":4};    //定义一个用户 的JSON
       var jsonStr = JSON.stringify(json);  //直接传JSON 传不过去,需要转义一下

//    JS调用安卓的方法,并且传递的参数为json格式的字符串(JSONObject.toString()),
//
//    例如: var json = {"name":"XJY","age":25",company":"CSII"};
//
//直接将json作为参数传递:window.name.jsToClient(json);
//
//        Android获取的参数是不可用的,打印出来的是undefinded。
//
//        JS要这样处理,再作为参数传递给原生:
//
//        var jsonStr = JSON.stringify(json);
//
//        window.name.jsToClient(jsonStr);
//
//        这样Android才能接受到json的字符串。

       function updateUser(){//更新用户
        JSTest.webapp_invoke("com.android.test2mvvm.test5.fragment7.dao.AppDatabase","updateUser",jsonStr);
        }
        function insertUser(){//插入用户
        JSTest.webapp_invoke("com.android.test2mvvm.test5.fragment7.dao.AppDatabase","insertUser",jsonStr);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

下面这是User的 bean:

public class User extends BaseObservable {

    @PrimaryKey
    private int uid;
    private String account;
    private String pwd;
    @Ignore
    private String confirmPwd;
    private String nickname;
    private String introduction;
    private String avatar;
.........//都是一键生成的代码
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这是AppDatabase数据库类:

@Database(entities = {User.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    private static final String DATABASE_NAME = "mvvm_demo.db";
    private static volatile AppDatabase mInstance;

    /**
     * 单例模式
     */
    public static AppDatabase getInstance(Context context) {
        if (mInstance == null) {
            synchronized (AppDatabase.class) {
                if (mInstance == null) {
                    mInstance = Room.databaseBuilder(context, AppDatabase.class, DATABASE_NAME).build();
                }
            }
        }
        return mInstance;
    }

    public static AppDatabase getInstance() {
        return mInstance;
    }

    public abstract UserDao userDao();

    public void getAllUser() {   //提供给JS调用
       Loge.e(userDao().getAll_01().toString());
    }

    public void updateUser(String jsonuser) {//提供给JS调用
        Loge.e(jsonuser+"------------");
        Gson gson = new Gson();
        User user = gson.fromJson(jsonuser, User.class);
        Loge.e(user.toString());
        userDao().update(user);
    }
    public void insertUser(String jsonuser){//提供给JS调用
        Loge.e(jsonuser+"------------");
        Gson gson = new Gson();
        User user = gson.fromJson(jsonuser, User.class);
        Loge.e(user.toString());
        userDao().insert(user);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

下面是DAO,操作room数据库 UserDao类:

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    LiveData<List<User>> getAll();

    @Query("SELECT * FROM user")
    List<User> getAll_01();

    @Query("select * from user where uid = 1")
    LiveData<User> getUser01();

    @Update
    void update(User user);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(User user);

    @Query("DELETE FROM user")
    void deleteAll();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

就这样,就完成了 在JS调用android原生的类 代码 操作。
来个效果截图:

在这里插入图片描述上面实现的功能随时增删改查,用户的UI可以每天多变,一点进去再下载新界面,一更新,又是一个新界面了。
在android 原生代码 尽量把工具类的常用功能实现。随时提供给JS 调用即可。JS方根据实际情况需求调用
当然,涉及到安全问题,在下载界面的时候加密即可,

关于使用Webview 内存泄露问题,我个人建议是,所有有使用WebView 的地方,统一放到另外一个activity 另开一个进程,退出activity 的时候,直接给它来个

  @Override
    protected void onDestroy() {
        super.onDestroy();
        Loge.e("退出");
        System.exit(0);//直接退出进程,一刀切了,干净省事。什么内存泄露,什么内存不够,等等玩意,都是不存在的。
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

activity另开进程代码:

  <activity
            android:name=".test6.Test6_Activity"
            android:process=":web" />
  • 1
  • 2
  • 3

就这么解决了webview 的痛点难点了。主进程和webview 的私有进程 互不干扰,重要数据用腾讯的 MMKV传过去即可,实时数据,AADL一个,,,进程之间一般也不会有多大的数据传递,不至于会影响用户体验。主进程尽量简便轻巧,主要是负责其他进程的入口,没事就挂着,也不会卡顿。负责push的进程 就学某多多,弄一个其他公司的logo,不让用户发觉,时不时的偷偷来广告。用户要怨恨,就怨恨其他公司去,哈哈,跟我某多多无关。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/824951
推荐阅读
相关标签
  

闽ICP备14008679号