首先需求是要做一个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