Git Product home page Git Product logo

rexxar-android's Introduction

Rexxar Android

Test Status IDE Android Language

Rexxar 是一个针对移动端的混合开发框架。现在支持 Android 和 iOS 平台。rexxar-android 是 Rexxar 在 Android 系统上的客户端实现。

通过 Rexxar,你可以使用包括 javascript,css,html 在内的传统前端技术开发移动应用。Rexxar 的客户端实现 Rexxar Container 对于 Web 端使用何种技术并无要求。我们现在的 Rexxar 的前端实现 Rexxar Web,以及 Rexxar Container 在两个平台的实现 rexxar-ios 和 rexxar-android 项目中所带的 Demo 都使用了 React。但你完全可以选择自己的前端框架在 Rexxar Container 中进行开发。

rexxar-android 现在支持 Android 4.0 及以上版本。

Rexxar 简介

关于 Rexxar 的整体介绍,可以看看这篇博客:豆瓣的混合开发框架 -- Rexxar

Rexxar 包含三个库:

使用

你可以查看 Demo 中的例子。了解如何使用 Rexxar。Demo 给出了完善的示例。

Demo 中使用 github 的 raw 文件服务提供一个简单的路由表文件 routes.json,demo.html 以及相关 javascript 资源的访问服务。在你的线上服务中,当然会需要一个真正的生产环境,以应付更大规模的路由表文件,以及 javascript,css,html 资源文件的访问。你可以使用任何服务端框架。Rexxar 对服务端框架并无要求。

安装

gradle

   compile 'com.douban.rexxar:core:0.6.9'

配置

1. 初始化

在Application的onCreate中调用

  Rexxar.initialize(Context context);

2. 设置路由表文件 api:

  RouteManager.getInstance().setRouteApi("https://raw.githubusercontent.com/douban/rexxar-web/master/example/dist/routes.json");

Rexxar 使用 uri 来标识页面,提供一个正确的 uri 就可以打开对应的页面,路由表提供了每个 uri 对应的 html 资源的下载地址。

Demo 中的路由表如下:

{
  "items": [
    {
      "deploy_time": "Sun, 09 Oct 2016 05:54:22 GMT",
      "remote_file": "https://raw.githubusercontent.com/douban/rexxar-web/master/example/dist/rexxar/demo-252452ae58.html",
      "uri": "douban://douban.com/rexxar_demo[/]?.*"
    }
  ],
  "partial_items": [
    {
      "deploy_time": "Sun, 09 Oct 2016 05:54:22 GMT",
      "remote_file": "https://raw.githubusercontent.com/douban/rexxar-web/master/example/dist/rexxar/demo-252452ae58.html",
      "uri": "douban://partial.douban.com/rexxar_demo/_.*"
    }
  ],
  "deploy_time": "Sun, 09 Oct 2016 05:54:22 GMT"
}

3. 设置需要代理或缓存的请求host

  ResourceProxy.getInstance().addProxyHosts(List<>() hosts);

Rexxar是通过WebViewClientshouldInterceptRequest方法来拦拦截请求,请求线上数据并返回给'webview'。为了减少不必要的流程破坏,只有明确需要拦截的hosts(支持正则)的请求才会被拦截代理,并根据mime-type决定哪些内容需要缓存。

4. 预置资源文件

使用 Rexxar 一般会预置一份路由表,以及资源文件在应用包中。这样就可以减少用户的下载,加快第一次打开页面的速度。在没有网络的情况下,如果没有数据请求的话,页面也可访问。这都有利于用户体验。 预置文件路径是assets/rexxar, 暂不支持修改。

使用 RexxarWebView

你可以直接使用 RexxarWebView 作为你的混合开发客户端容器。或者你也可以在 RexxarWebView 基础上实现你自己的客户端容器。

为了初始化 RexxarWebView,你需要只一个 url。在路由表文件 api 提供的路由表中可以找到这个 url。这个 url 标识了该页面所需使用的资源文件的位置。Rexxar Container 会通过 url 在路由表中寻找对应的 javascript,css,html 资源文件。

  // 根据uri打开指定的web页面
  mWebView.loadUri("douban://douban.com/rexxar_demo");

定制你自己的 Rexxar Container

我们暴露了三类接口。供开发者更方便地扩展属于自己的特定功能实现。

定制 RexxarWidget

Rexxar Container 提供了一些原生 UI 组件,供 Rexxar Web 使用。RexxarWidget 是一个 Java 协议(Protocol)。该协议是对这类原生 UI 组件的抽象。如果,你需要实现某些原生 UI 组件,例如,弹出一个 Toast,或者添加原生效果的下拉刷新,你就可以实现一个符合 RexxarWidget 协议的类,并实现以下方法:getPath:, handle:

在 Demo 中可以找到一个例子:TitleWidget ,通过它可以设置导航栏的标题文字。

    public class TitleWidget implements RexxarWidget {

    static final String KEY_TITLE = "title";

    @Override
    public String getPath() {
        return "/widget/nav_title";
    }

    @Override
    public boolean handle(WebView view, String url) {
        if (TextUtils.isEmpty(url)) {
            return false;
        }
        Uri uri = Uri.parse(url);
        if (TextUtils.equals(uri.getPath(), getPath())) {
            String title = uri.getQueryParameter(KEY_TITLE);
            if (null != view && view.getContext() instanceof Activity) {
                ((Activity)view.getContext()).setTitle(Uri.decode(title));
            }
            return true;
        }
        return false;
    }
}

定制 RexxarContainerAPI

我们常常需要在 Rexxar Container 和 Rexxar Web 之间做数据交互。比如 Rexxar Container 可以为 Rexxar Web 提供一些计算结果。如果你需要提供一些由原生代码计算的数据给 Rexxar Web 使用,你就可以选择实现 RexxarContainerAPI 协议(Protocol),并实现以下三个方法:getPath:, call:

在 Demo 中可以找到一个例子:LocationAPI。这个例子中,LocationAPI 返回了设备所在城市信息。当然,这个 ContainerAPI 仅仅是一个示例,它提供的是一个假数据,数据永远不会变化。你当然可以遵守 RexxarContainerAPI 协议,实现一个类似的但是数据是真实的功能。

    static class LocationAPI implements RexxarContainerAPI {

        @Override
        public String getPath() {
            return "/loc";
        }

        @Override
        public Response call(Request request) {
            Response.Builder responseBuilder = newResponseBuilder(request);
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("lat", "0.0");
                jsonObject.put("lng", "0.0");
                responseBuilder.body(ResponseBody.create(MediaType.parse(Constants.MIME_TYPE_JSON), jsonObject.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return responseBuilder.build();
        }
    }

定制 Rexxar Decorator

如果你需要修改运行在 Rexxar Container 中的 Rexxar Web 所发出的请求。例如,在 http 头中添加登录信息,你可以自定义OkHttpClient,Rexxar.setOkHttpClient(OkHttpClient okHttpClient)

在 Demo 中可以找到一个例子:AuthInterceptor。这个例子为 Rexxar Web 发出的请求添加了登录信息。

    public class AuthInterceptor implements Interceptor{

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            String url = request.url().toString();
            if (TextUtils.isEmpty(url)) {
                return null;
            }

            Request.Builder builder = request.newBuilder();
            builder.header("Authorization", "123456789");
            return chain.proceed(builder.build());
        }
    }

    // Rexxar初始化时设置
    Rexxar.setOkHttpClient(new OkHttpClient().newBuilder()
            .retryOnConnectionFailure(true)
            .addNetworkInterceptor(new AuthInterceptor())
            .build());

高级使用

native调用js方法


    // 方法名
    RexxarWebView.callFunction(String functionName)
    
    // 方法名和json数据
    RexxarWebView.callFunction(String functionName, String jsonString)
    

Partial RexxarWebView

如果,你发现一个页面无法全部使用 Rexxar 实现。你可以在一个原生页面内内嵌一个 RexxarWebView,部分功能使用原生实现,另一部分功能使用 Rexxar 实现。

Demo 中的 PartialRexxarViewController 给出了一个示例。

License

Rexxar is released under the MIT license. See LICENSE for details.

rexxar-android's People

Contributors

emanonwzy avatar mcxiaoke avatar qluan avatar xiaolongyuan avatar yimun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rexxar-android's Issues

RouteManager中的单例模式写的应该是不对的

private static RouteManager sInstance;//这种写法静态变量应该用volatile修饰,不然指令重排序可能导致其他线程获取到错误的单例,可以看一下这里说明:https://my.oschina.net/u/2250599/blog/412827
public static RouteManager getInstance(boolean asyncLoadRoute) {
        if (null == sInstance) {
            synchronized (RouteManager.class) {
                if (null == sInstance) {
                    sInstance = new RouteManager(asyncLoadRoute);
                }
            }
        }
        return sInstance;
 }

js 缓存失败

 经常出现缓存问题 手机型号 奇虎360 N4s android版本:6.0.1 服务器express
d

Intercepter 添加 headers 信息不成功

你好,我在web端使用的是axios的一个ajax库,在android端希望通过添加headers信息来处理登录状态。可是服务器端并未能接收到headers的修改信息。


测试发现fetch加headers是可以成功添加的。

请问是不支持ajax加headers吗?

为何RexxarContainerAPI设计为全局有效?

目前无法对不同的RexxarWebViewClient实例设置不同的RexxarContainerAPI,请问是特意如此设计的吗?

目前在使用时遇到一些不便之处:

例如实际想请求的url为:http://xxx.com/detail.html?id=1 , 目前我采用的方式是使用rexxar打开http://xxx.com/detail.html , 然后通过RexxarContainerAPI传入id=1的参数。 http://xxx.com/detail.html 中的js脚本拿到id后再请求数据并显示。

请问上述使用方法是否符合rexxar的设计初衷?

如果是的话,可能对不同的RexxarWebViewClient实例设置不同的RexxarContainerAPI更加灵活一些。

如果我的使用方法有问题,请不吝赐教。

建议修改

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        LogUtils.i(TAG, "[shouldOverrideUrlLoading] : url = " + url);
        if (url.startsWith(Constants.getContainerWidgetBase())) {
            boolean handled;
            for (RexxarWidget widget : mWidgets) {
                if (null != widget) {
                    handled = widget.handle(view, url);
                    if (handled) {
                        return true;
                    }
                }
            }
        }
        return super.shouldOverrideUrlLoading(view, url);
    }

这个方法写的太死了 主要是放开 schema

xss漏洞

AlertDialogWidget.java中利用了javascript伪协议
图片
攻击者可以通过控制data来执行任意javascript代码

POST 请求 处理有BUG 会导致 参数发送两遍

image

15:40:03.918 DEBUG c.q.web.filter.HttpRequestLogFilter[95] - Debug information: 
 HTTP Request Method         :POST
 HTTP Request NODE           :192.168.199.78
 HTTP Request URI            :/api/v1/auth/security/tradepasswd/update
 HTTP Request Query String   :sessionId=17904c6b-8f66-45b4-ac69-e9203e6c0f47&password=111111&smsCaptcha=123456&_rexxar_method=POST
 HTTP Request Remote HOST    :192.168.199.247
 HTTP Request Parameter List : 
 - sessionId=17904c6b-8f66-45b4-ac69-e9203e6c0f47,17904c6b-8f66-45b4-ac69-e9203e6c0f47
 - password=111111,111111
 - smsCaptcha=123456,123456
 - _rexxar_method=POST,POST
 HTTP Request Header List : 
 - content-length=100,
 - x-client-platform=Android,
 - x-client-version=1.0.1,
 - cookie=token_id=4d305f16-c340-4142-a2dc-5fb7b98ad853; token_type=USER; token_uid=100001,
 - x-client-git-sha=b6ada54b,
 - x-client-build=1001,
 - host=192.168.199.78:8888,
 - content-type=application/x-www-form-urlencoded,
 - connection=Keep-Alive,
 - accept-encoding=gzip,
 - user-agent=Rexxar-Core/0.1.3  Rexxar/1.2.0

url 参数一遍
POST 请求体又一遍
晕 这么大的bug 你确定 你们生产这么访问API?

如何处理两个H5页面的跳转?

a.html 跳转到 b.html, 是通过拦截a.html中的跳转请求,在原生层中转换成以startActivity的方式去启动另一个Container吗?这样的话,H5页面的跳转协议是不是要写两套呢?在浏览中运行时是一套,在手机端中运行时是另一套?

希望能提供一个较复杂的示例参考。

Android 数据请求问题

我发现一个bug 开发时直接使用 url 加载访问 webpack进行热更新后 :
使用库:axios (使用 rexxar 自带的 fetch一样)

问题 网络请求的数据没有返回给对应的webview
使用 chrome://inspect/#devices 发现检测到多个web

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.