android 学习之路h5混合开发项目经历

首先需求是要做一个h5调用原生去发送udp mqtt 存储 tcp 相机之类的功能

第一步在mainActivity 注册监听

private void initWebLoad(String url) {
        Util.synCookies(getApplicationContext(), url, SharePreferenceUtils.getPrefString(getApplicationContext(), SharePreferenceUtils.WEB_VIEW_COOKIE, ""));
        //第一个参数为用户名,第二个参数为密码
        final String basic = Credentials.basic("zhangsan", "123456");
        Map<String, String> heads=new HashMap<>();
        heads.put("Authorization",basic);
        bridgeWebView2.loadUrl(url,heads);

        ShakeService shakeService=ARouter.getInstance().navigation(ShakeService.class);
        if(shakeService!=null){
            shakeService.handleShake(this);
            //调试
            if(Build.VERSION.SDK_INT> Build.VERSION_CODES.KITKAT) {
                bridgeWebView2.setWebContentsDebuggingEnabled(true);
            }
        }

        getPresenter().registerH5CallNative(bridgeWebView2);
    }

第二步 在MainPresenter p层做registerH5CallNative方法的实现

/**
     * H5调用原生
     * @param bridgeWebView
     */
    public void registerH5CallNative(final WVJBWebView bridgeWebView) {
        bridgeWebView.registerHandler(REGISTER_HANDLE_NAME, new WVJBWebView.WVJBHandler() {
            @Override
            public void handler(Object dataobj, WVJBWebView.WVJBResponseCallback function) {

                String data=dataobj.toString();
                functionMap.put(function.toString(),function);
                try {
                    Timber.e(TAG, "##H5CallNative 收到: " + data);
                    String service = Util.getService(data);
                    Timber.e(TAG, service);
                    String action = Util.getAction(data);
                    Timber.e(TAG,action);
                    LinkedTreeMap messageTreeMap = GsonUtils.getJsonLinkedTree(data);
                    String message = "";
                    if (messageTreeMap != null) {
                        message = GsonUtils.getJsonString(messageTreeMap.get("data"));
                    }
                    Timber.e(TAG,message);
                    switch (service){
                        case SERVICE_HTTP:
                        case SERVICE_FILE:
                            if(httpService==null) {
                                httpService = ARouter.getInstance().navigation(HttpService.class);
                            }
                            if(httpService!=null){
                                httpService.handleData(function.toString(),getActivity(),action,message);
                            }
                            break;
                        case SERVICE_UDP:
                            if(udpService==null) {
                                udpService = ARouter.getInstance().navigation(UdpService.class);
                            }
                            if(udpService!=null){
                                udpService.handleData(action,message);
                            }
                            break;
                        case SERVICE_MQTT:
                            if(mqttService==null){
                                mqttService=ARouter.getInstance().navigation(MqttService.class);
                            }
                            if(mqttService!=null){
                                mqttService.handleData(function.toString(),action,message);
                            }
                            break;
                            //数据存储
                        case SERVICE_DATA:
                        case SERVICE_DATA_BASE:
                            if(databaseService==null){
                                databaseService=ARouter.getInstance().navigation(DatabaseService.class);
                            }
                            if(databaseService!=null){
                                databaseService.handleData(function.toString(),action,message);
                            }
                            break;
                        case SERVICE_SYSTEM:
                            if(systemService==null){
                                systemService=ARouter.getInstance().navigation(SystemService.class);
                            }
                            if(systemService!=null){
                                systemService.handleData(function.toString(),getActivity(),action,message);
                            }
                            break;
                        case SERVICE_SMARTLINK:
                            if(smartLinkService==null){
                                smartLinkService=ARouter.getInstance().navigation(SmartLinkService.class);
                            }
                            if(smartLinkService!=null){
                                smartLinkService.handleData(function.toString(),action,message);
                            }
                            break;
                        case SERVICE_TCP:
                            if(tcpService==null){
                                tcpService=ARouter.getInstance().navigation(TcpService.class);
                            }
                            if(tcpService!=null){
                                tcpService.handleData(function.toString(),action,message);
                            }
                            break;
                        case SERVICE_CAMERA:
                            if(cameraService==null){
                                cameraService=ARouter.getInstance().navigation(CameraService.class);
                            }
                            if(cameraService!=null){
                                cameraService.handleData(function.toString(),getActivity(),action,message);
                            }
                            break;
                        case SERVICE_APPUPGRADE:
                            if(upgradeService==null){
                                upgradeService=ARouter.getInstance().navigation(UpgradeService.class);
                            }
                            if(upgradeService!=null){
                                upgradeService.handleData(getActivity(),function.toString(),action,message);
                            }
                            break;
                        case SERVICE_MAP:
                            if(mapService==null){
                                mapService=ARouter.getInstance().navigation(MapService.class);
                            }
                            if(mapService!=null){
                                mapService.handleData(function.toString(),getActivity(),action,message);
                            }
                            break;
                        case SERVICE_BLE:
                            if(bleService==null){
                                bleService=ARouter.getInstance().navigation(BleService.class);
                            }
                            if(bleService!=null){
                                bleService.handleData(function.toString(),action,message);
                            }
                            break;
                        case SERVICE_CLIENT:
                            if(ipcService==null){
                                ipcService=ARouter.getInstance().navigation(IpcService.class);
                            }
                            if(ipcService!=null){
                                if(ACTION_TO_START.equals(action) ){
                                    if(getView()!=null){
                                        getView().addVideoFragment(message);
                                    }
                                }
                                ipcService.handleData(getActivity(),function.toString(),service,action,message);
                            }
                            break;
                        case SERVICESD_CARD:
                            if(ipcService==null){
                                ipcService=ARouter.getInstance().navigation(IpcService.class);
                            }
                            if(ipcService!=null){
                                ipcService.handleData(getActivity(),function.toString(),service,action,message);
                            }
                            break;
                        case SERVICE_STATUSBAR:
                            final LinkedTreeMap linkedTreeMap =GsonUtils.getJsonLinkedTree(message);
                            switch (action){
                                case ACTION_ROTATE:
                                    //1竖屏,0横屏
                                    int orientation = -1;
                                    if (linkedTreeMap != null) {
                                        if (linkedTreeMap.containsKey("orientation")) {
                                            orientation = (int) Double.parseDouble(linkedTreeMap.get("orientation").toString());
                                            if(orientation==0){
                                                getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//横屏
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }else if(orientation==1){
                                                getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }
                                        }
                                    }
                                    break;
                                case ACTION_STATE:
                                    //1显示,0隐藏
                                    int isVisible = -1;
                                    if (linkedTreeMap != null) {
                                        if (linkedTreeMap.containsKey("isVisible")) {
                                            isVisible = (int) Double.parseDouble(linkedTreeMap.get("isVisible").toString());
                                            if(isVisible==0){
                                                getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //隐藏状态栏
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }else if(isVisible==1){
                                                getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //显示状态栏
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }
                                        }
                                    }
                                    break;
                                case ACTION_STYLE:
                                    //1黑色,0白色
                                    int setStyle = -1;
                                    if (linkedTreeMap != null) {
                                        if (linkedTreeMap.containsKey("setStyle")) {
                                            setStyle = (int) Double.parseDouble(linkedTreeMap.get("setStyle").toString());
                                            if(setStyle==0){
                                                StatusBarUtil.setLightMode(getActivity());
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }else if(setStyle==1){
                                                StatusBarUtil.setDarkMode(getActivity());
                                                callH5Callback(function.toString(),"{\"code\":200}");
                                            }
                                        }
                                    }
                                    break;
                            }
                            break;
                        case SERVICE_EXTERNAL:
                            if(externalService==null){
                                externalService=ARouter.getInstance().navigation(ExternalService.class);
                            }
                            if(externalService!=null){
                                externalService.handleData(getActivity(),function.toString(),action,message);
                            }
                            break;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

    }

第三步 在对应的service serviceImpl中实现其方法,举例说udpservice udpserviceImpl

public interface UdpService extends IProvider {
    void handleData(String action, String data);
}

udpserviceImpl去实现handleData方法

public class UdpServiceImpl implements UdpService {
    private static final String TAG = "UdpServiceImpl";
    private Context context;
    private static final String ACTION_SEND="send";

    public static final String ACTION_LISTEN="listen";
    public static final String ACTION_CLOSE="close";
    private static final String H5_MODULE_UDP="UDP";
    private static final String H5_ACTION_PUSH_MESSAGE = "pushMessage";
    @Override
    public void handleData( String action, String data) {
//        Log.e(TAG,action+"------data:"+data);
        switch (action){
            case ACTION_SEND:
                final LinkedTreeMap linkedTreeMap = GsonUtils.getJsonLinkedTree(data);
                String ip = "";
                int port = 0;
                String msg = "";
                if (linkedTreeMap != null) {
                    ip = linkedTreeMap.get("ip").toString();
                    if(linkedTreeMap.containsKey("port"))
                        port = (int) Double.parseDouble(linkedTreeMap.get("port").toString());
                    msg = GsonUtils.getJsonString(linkedTreeMap.get("message"));

                    LinkedTreeMap t = GsonUtils.getJsonLinkedTree(msg);
                    String method = t.get("method").toString();
                    if (method.equals("devDiscoveryReq")) {
                        UDPManager.getInstance().ScanDevice(context, port, msg, new UdpResponseListener() {
                            @Override
                            public void onResponse(final String m) {
                                EventBus.getDefault().post(new JsCallH5ByNativeEvent(H5_MODULE_UDP,H5_ACTION_PUSH_MESSAGE,m));
                            }

                            @Override
                            public void onTimeOut() {

                            }

                            @Override
                            public void onError(Exception e) {

                            }
                        });
                    } else {
                        int timeout;
                        if (method.equals("wifiListReq")) {
                            timeout=20000;
                        }else{
                            timeout=-1;
                        }
                        UDPManager.getInstance().sendAsyn(context, ip, port,timeout, msg, new UdpResponseListener() {
                            @Override
                            public void onResponse(final String m) {
                                EventBus.getDefault().post(new JsCallH5ByNativeEvent(H5_MODULE_UDP,H5_ACTION_PUSH_MESSAGE,m));
                            }

                            @Override
                            public void onTimeOut() {

                            }

                            @Override
                            public void onError(Exception e) {

                            }
                        });
                    }
                }
                break;
            case ACTION_LISTEN:
                final LinkedTreeMap linkedTreeMap2 = GsonUtils.getJsonLinkedTree(data);
                int port2 = 0;
                if (linkedTreeMap2 != null) {
                    port2 = (int) Double.parseDouble(linkedTreeMap2.get("port").toString());
                    //listenAsyn
                    UDPManager.getInstance().nioListen( port2, new UdpResponseListener() {
                        @Override
                        public void onResponse(String message) {
                            EventBus.getDefault().post(new JsCallH5ByNativeEvent(H5_MODULE_UDP, H5_ACTION_PUSH_MESSAGE, message));
                        }

                        @Override
                        public void onTimeOut() {

                        }

                        @Override
                        public void onError(Exception e) {

                        }
                    });
                }
                break;
            case ACTION_CLOSE:
//                UDPManager.getInstance().StopListen();
                UDPManager.getInstance().stopNioListen();

                break;
        }
    }

    @Override
    public void init(Context context) {
        this.context=context;
//        Log.e(TAG, "init: " );
    }
}

将h5传过来的json转换成map 通过对应key取出来

  final LinkedTreeMap linkedTreeMap = GsonUtils.getJsonLinkedTree(data);
  public static LinkedTreeMap getJsonLinkedTree(String jsonData) {
        if (TextUtils.isEmpty(jsonData)) {
            return null;
        }
        Gson gson = new GsonBuilder()
                .disableHtmlEscaping().create();
        LinkedTreeMap map = gson.fromJson(jsonData, LinkedTreeMap.class);
        return map;
    }

根据不同的参数调用udp的不同方法 这边举例讲send

 UDPManager.getInstance().sendAsyn(context, ip, port,timeout, msg, new UdpResponseListener() {
                            @Override
                            public void onResponse(final String m) {
                                EventBus.getDefault().post(new JsCallH5ByNativeEvent(H5_MODULE_UDP,H5_ACTION_PUSH_MESSAGE,m));
                            }

                            @Override
                            public void onTimeOut() {

                            }

                            @Override
                            public void onError(Exception e) {

                            }
                        }

第四步 在UDPManager中去实现send方法 因为防止线程阻塞 异步发送 

 /**
     * 异步发送
     */
    public void sendAsyn(final Context context, final String ip, final int port, final int timeout, final String message, final UdpResponseListener responseListener) {
        this.context=context;
        thread = null;
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    send(ip, port,timeout, message, responseListener);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }

具体实现udp发送数据及收到数据方法 new ds一个DatagramSocket对象 用来发送udp new 两个DatagramPacket 一个dp_send用来储藏发送数据,一个dp_receive用来接收数据,

  private void send(String ip, int port, int timeout, String message, UdpResponseListener responseListener) throws IOException {
//        Log.e(TAG, "send 发送udp数据: " );
        byte[] buf = new byte[10240];
        DatagramSocket ds = new DatagramSocket();
        InetAddress loc = InetAddress.getLocalHost();
        try {
            if (TextUtils.isEmpty(ip)) {
                loc = InetAddress.getByName("255.255.255.255");
            } else {
                loc = getAddressByString(ip);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //定义用来发送数据的DatagramPacket实例
        DatagramPacket dp_send = new DatagramPacket(message.getBytes(), message.length(), loc, port);
        //定义用来接收数据的DatagramPacket实例
        DatagramPacket dp_receive = new DatagramPacket(buf, 10240);
        //数据发向本地36877端口
        if(timeout<0) {
            ds.setSoTimeout(TIMEOUT);              //设置接收数据时阻塞的最长时间
        }else{
            ds.setSoTimeout(timeout);
        }
        int tries = 0;                         //重发数据的次数
        boolean receivedResponse = false;     //是否接收到数据的标志位
        //直到接收到数据,或者重发次数达到预定值,则退出循环
        while (!receivedResponse && tries < MAXNUM) {
            //发送数据
            ds.send(dp_send);
            try {
                //接收从服务端发送回来的数据
                ds.receive(dp_receive);
                String strMsg=new String(dp_receive.getData()).trim();
//                Log.e("##########", dp_receive.getAddress()
//                        .getHostAddress().toString()+dp_receive.getPort()
//                        + ":" +strMsg );
                //如果接收到的数据不是来自目标地址,则抛出异常
//                if (!"/255.255.255.255".equals(loc.toString()) && !dp_receive.getAddress().equals(loc)) {
//                    throw new IOException("Received packet from an umknown source" + loc.toString() + "  receiver Address:" + dp_receive.getAddress());
//                }
                //如果接收到数据。则将receivedResponse标志位改为true,从而退出循环
                receivedResponse = true;
            } catch (InterruptedIOException e) {
                e.printStackTrace();
                //如果接收数据时阻塞超时,重发并减少一次重发的次数
                tries += 1;
//                Log.e("duyucheng", "Time out," + (MAXNUM - tries) + " more tries...");
            }
        }
        if (receivedResponse) {
            //如果收到数据,则打印出来
//            Log.e("duyucheng", "client received data from server:");
            String str_receive = new String(dp_receive.getData(), 0, dp_receive.getLength());
            String device_ip=dp_receive.getAddress().getHostAddress().toString();
            int rec_port=dp_receive.getPort();
            try {
                JSONObject jsonObject1=new JSONObject(str_receive);
                JSONObject paloadObject=jsonObject1.getJSONObject("payload");
                paloadObject.put("ip",device_ip);
                paloadObject.put("port",rec_port);
                str_receive =jsonObject1.toString();
            }catch (Exception e){
                e.printStackTrace();
            }
            //由于dp_receive在接收了数据之后,其内部消息长度值会变为实际接收的消息的字节数,
            //所以这里要将dp_receive的内部消息长度重新置为1024
            dp_receive.setLength(1024);
            if (responseListener != null) {
                responseListener.onResponse(str_receive);
            }
        } else {
            //如果重发MAXNUM次数据后,仍未获得服务器发送回来的数据,则打印如下信息
//            Log.e("duyucheng", "No response -- give up.");
            if (responseListener != null) {
                responseListener.onError(null);
            }
        }
        ds.close();
    }

第五步  在第三步的send方法 成功用eventbus 将数据发送出来,自己先new一个事件类JsCallH5ByNativeEvent,并在mainActivity中注册 EventBus.getDefault().register(this); 

 UDPManager.getInstance().sendAsyn(context, ip, port,timeout, msg, new UdpResponseListener() {
                            @Override
                            public void onResponse(final String m) {
                                EventBus.getDefault().post(new JsCallH5ByNativeEvent(H5_MODULE_UDP,H5_ACTION_PUSH_MESSAGE,m));
                            }

                            @Override
                            public void onTimeOut() {

                            }

                            @Override
                            public void onError(Exception e) {

                            }
                        }
public class JsCallH5ByNativeEvent {
    private String service;
    private String action;
    private String data;
    public JsCallH5ByNativeEvent(String service,String action,String data){
        this.service=service;
        this.action=action;
        this.data=data;
    }

    public String getService() {
        return service;
    }

    public void setService(String service) {
        this.service = service;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}
EventBus.getDefault().register(this);

第六步 在mainActivity中监听eventBus发送的数据

@Subscribe(threadMode=ThreadMode.MAIN)
    public void onJsCallH5ByNative(JsCallH5ByNativeEvent event){
        if (event != null&&getPresenter()!=null) {
            getPresenter().callH5ByNavite(bridgeWebView2,event.getService(),event.getAction(),event.getData());
        }
    }

第七步 将数据转换成json发送给h5端

 /**
     * 原生发数据到H5
     * @param service
     * @param action
     * @param data
     */

    public void callH5ByNavite(final WVJBWebView bridgeWebView, String service, String action, String data) {
        JsonObject jsonBean = null;
        if (!TextUtils.isEmpty(data)) {
            try {
                jsonBean = new JsonParser().parse(data).getAsJsonObject();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        H5NativeBean h5NativeBean = new H5NativeBean();
        h5NativeBean.setService(service);
        h5NativeBean.setAction(action);
        h5NativeBean.setData(jsonBean);
        final String message = GsonUtils.getJsonString(h5NativeBean);
        Timber.e("%%callH5ByNavite 发到H5: " + message);
        if(getActivity()!=null&&bridgeWebView!=null){
            bridgeWebView.callHandler(HANDLER_CALL_NATIVE, message);
        }
    }

搞定 !!!  

涉及到的知识点有

1 service接口+serviceImpl实现类 "高扩展性”。

2 mvp模式 

Activity 和Fragment 视为View层,负责处理 UI。

Presenter 为业务处理层,既能调用UI逻辑,又能请求数据,该层为纯Java类,不涉及任何Android API。

Model 层中包含着具体的数据请求,数据源。

3 Handler

4 广播

5 异步

6 udp

7 eventBus

猜你喜欢

转载自blog.csdn.net/qq_32114025/article/details/84935769