* 由于最近项目中貌似需要做这一块,于是就去读了一下云之讯官方测试Demo的音频版的源码[Android音频版](http://www.ucpaas.com/product_service/download)。
* 其实这个Demo并不是什么高大上的代码,也没有很多生涩难懂的代码在里面,相反,读起来还是很轻松的。
* 不过,虽然代码结构清晰,但是里面的广播实在太多。如果不去理一理,确实不太好明白到底流程是怎样的。不过,好在Demo中还提供了一个Activity的结构图,也是辅助大家去做进一步的理解。
* 基于这些辅助,以及代码中的关键注释,差不多将其中的操作流程理清楚了。这里就贴出来欣赏欣赏这样一个Demo的逻辑流程。不过由于其中的代码太多,我只读了Activity结构图的第一条线的代码。(网络电话)这条线相对简单,其他的线代码量更大,就没有去读了。
* application logic
1. 当application被打开的时候,就开启了一个服务ConnectionService.{ConnectionService服务的逻辑:* 1.在服务创建的时候,就添加了一些监听器,注册了广播接收器* 1.1.添加若干监听器: 连接的监听,消息的监听,通话的监听* 1.2.开启了一个广播接收器,接收4条广播。接收广播: UIDfineAction.ACTION_LOGIN&& UIDfineAction.ACTION_DIAL&& UCSService.ACTION_INIT_SUCCESS&& android.intent.action.ACTION_SHUTDOWN  // 系统关机广播* 2.在该广播中,处理逻辑为:*  1. action== UIDfineAction.ACTION_LOGIN;* 1. 如果当前有通话,则挂断;* 2.从收到的意图对象intent中获取传递的cliend_id,cliend_pwd,sid,sid_pwd的值,并赋值给当前类定义的成员变量!* 3. 根据这4个值,分情况进行不同方式的(非token方式/token方式)“通接云之讯通信平台”。1. 4个值都有,就进行非token的方式进行连接->开子线程,调用sdk提供的(非token的方式)connect函数,进行连接云之讯通信平台。2. 4个值,cliend_id与cliend_pwd没有,进行token方式的连接->开子线程,调用sdk提高的(token方式的)connect函数,进行连接云之讯通信平台。============ACTION_LOGIN的逻辑处理完毕。2. action== UIDfineAction.ACTION_DIAL1. 从收到的意图对象intent中获取传递的type,call_uid,call_phone的值。2. 根据type的值,做不同的逻辑操作。// type: 0:直拨    1:免费 2:回拨    3:视频点对点 4:会议    5:智能拨打case 0://0:直拨UCSCall.dial(ConnectionService.this, CallType.DIRECT, phone);case 1://1:免费UCSCall.dial(ConnectionService.this, CallType.VOIP, uid,"欢迎加入云之讯");       case 2:  //2:回拨UCSCall.callBack(ConnectionService.this, phone, fromSerNum,toSerNum);case 3: 无逻辑case 4:1. 根据传递的意图对象intent获取callType的值。2. 根据callType值的不同,分别开启不同的UCSCall.startChatRoom(,callType,);case 5:UCSCall.dial(ConnectionService.this, CallType.CALL_AUTO,phone);==================ACTION_DIAL的逻辑处理完毕。3. action== android.intent.action.ACTION_SHUTDOWN1.停止响铃2.断开通话==================ACTION_SHUTDOWN的逻辑处理完毕。3.onConnectionFailed(UcsReason reason)连接失败或断线的回调方法的逻辑处理:1. 取消定时器,将定时器置空(// TODO ------------->)2. 发送广播意图动作action==UIDfineAction.ACTION_TCP_LOGIN_CLIENT_RESPONSE,并携带数据(UIDfineAction.RESULT_KEY, 1),以及(UIDfineAction.REASON_KEY, reason.getReason());3. 根据该回调方法的参数reason的getReason()获取的值,去判断,如果getReason()==300505||300207,就发送广播,发送的广播意图动作action==UIDfineAction.ACTION_LOGOUT,并携带数据(UIDfineAction.REASON_KEY, reason.getReason());并创建意图进行Activity跳转,跳转到TerminalLoginDialogActivity,同时携带数据("reason",reason.getReason());4.onConnectionSuccessful()连接成功回调方法的处理逻辑1. 将IMMessageActivity.msgList 中的数据清空2. 发送广播,action== UIDfineAction.ACTION_TCP_LOGIN_CLIENT_RESPONSE,并携带数据(UIDfineAction.RESULT_KEY, 0);3. 判断当前成员变量cliend_id有没有被赋值,如果有,就保存到sp文件中(文件名:yunzhixun_demo);5.onAlerting(String arg0)对方正在响铃的回调方法的逻辑处理1. 发送广播,action== UIDfineAction.ACTION_DIAL_STATE,并携带数据("state", UCSCall.CALL_VOIP_RINGING_180);6.onAnswer(String arg0)对方接通的回调方法的逻辑处理1. 发送广播,action== UIDfineAction.ACTION_ANSWER2. 开启定时器记录通话时长,每隔1秒发送一次广播action== UIDfineAction.ACTION_CALL_TIME,并携带数据("callduration",hour * 3600 + minute * 60 + second),以及("timer", timer.toString());7.onDialFailed(String arg0, UcsReason reason)拨打失败的回调方法的逻辑处理1. 根据reason.getReason()的值分别发送不同的广播:case 300210:sendBroadcast(new Intent(UIDfineAction.ACTION_DIAL_STATE).putExtra("state", UCSCall.CALL_VOIP_ERROR));break;case 300211:sendBroadcast(new Intent(UIDfineAction.ACTION_DIAL_STATE).putExtra("state", UCSCall.CALL_VOIP_NOT_ENOUGH_BALANCE));break;case 300212:sendBroadcast(new Intent(UIDfineAction.ACTION_DIAL_STATE).putExtra("state", UCSCall.CALL_VOIP_BUSY));break;case 300213:xxxx,后面还有很多case 不一一列举======反正都是发广播说明拨打失败的原因8. onHangUp(String arg0, final UcsReason reason) 回调方法的逻辑处理1. 根据arg0的值是否为空,并且是否与成员变量lastIncomingCallId相等,并且当前系统时间毫秒值与lastIncomingCallTime相差不到1000毫秒Y 如果以上成立,就过1000-(系统当前时间毫秒值与lastIncomingCallTime的差值)之后,停止响铃,并发送广播,发送广播的action== UIDfineAction.ACTION_DIAL_HANGUP,并携带数据("state", reason.getReason());N 如果以上不成了,就直接发送广播,action== UIDfineAction.ACTION_DIAL_HANGUP,并携带数据("state", reason.getReason());2. 走onDialFailed(String arg0, UcsReason reason)拨打失败的回调中相同的逻辑(发送广播说明失败的原因)3. 取消定时器(onAnswer(String arg0)对方接通的回调方法中创建的定时器)9. onIncomingCall(String callId, String callType,String callerNumber, String nickName, String userdata) 回调方法的逻辑处理:1. 休眠1秒2. lastIncomingCallId = callId;将callId赋值给成员变量lastIncomingCallId3. lastIncomingCallTime = System.currentTimeMillis();将系统当前时间的毫秒值赋值给成员变量lastIncomingCallTime4. 根据传入的callType判断,如果callType.equals("0"),就开启Activity-->AudioConverseActivity如果callType.equals("2"),就开启Activity-->ConferenceConverseActivity//会议无论开启那个Activity,都携带数据("phoneNumber", callerNumber),以及("inCall", true),以及("nickName", nickName);10. onReceiveUcsMessage(UcsReason reason, UcsMessage message) 接收新消息回调方法的逻辑处理:1. 如果reason.getReason() == 0,就:将信息存放到IMMessageActivity.msgList集合中否则:log输出下载文件失败...11.xxx后面还有3,4个回调方法,不一一解释了      }---------------------
2. 当application打开的时候,不仅开启了上面的服务,还打开的欢迎界面,在欢迎界面停留了两秒钟之后,自动跳转到了登录界面LoginActivity
3. LoginActivity的逻辑{1.LoginActivity.onCreate(bundle)方法1. 注册广播接收器,接收如下广播:接收广播: UIDfineAction.ACTION_TCP_LOGIN_RESPONSE&&UIDfineAction.ACTION_TCP_LOGIN_CLIENT_RESPONSE2. 实例化用户名和密码的输入框EditText3. 从sp文件中获取存放过的用户名和密码。(首次登录就获取不到)Y  如果获取到了:就判断开启当前Activity的意图有没有携带数据("AutoLogin", false),并且值为true,同时,成员变量mLoginDialog==null,那么,就1. 判断一下当前的用户是个人开发者还是企业开发者。2. 开启一个定时器,30秒后发送一个what=0的message给handler。3. 弹出对话框显示"正在获取测试账号,请稍等...",并立即关闭对话框。4. 开启一个匿名子线程,在子线程中做如下逻辑:1. 判断当前开发者是个人开发者还是企业开发者2. 将用户名和密码以及时间戳等参数以post的方式,发送http请求给指定的URL,获取一个response对象,通过response对象,获取其中的json字符串。3. 对获取的json字符串进行操作0. 设立局部变量result=1;   0.5 判断该json是否含有节点resp,如果有进行后续1,如果没有,不走1。1. 判断该json中是否有节点respCode,并且节点值为equals("000000"),如果成立,就将json串中的sid,token,appId,client,client_number,client_pwd,mobile等信息写进文件 xxx/config.properties中。并将局部变量result赋值为0;如果不成立,就判断当前json是否包含节点respCode,并将节点值转车int赋值给result2. 最后,无论有没有走1,都会做一件事:发送广播发送广播的action== UIDfineAction.ACTION_TCP_LOGIN_RESPONSE,并携带数据(UIDfineAction.RESULT_KEY, result);N  如果没有获取到:就不做任何逻辑操作。4. 绑定登录按钮的点击事件:1.登录按钮的点击事件的逻辑:1.检查网络,如果没有联网,吐司提醒网络异常;如果有联网,就走上面获取到sp中【用户名和密码,并且("AutoLogin", false),的值为true,mLoginDialog==null,】的相同逻辑上面的1,2,3,4(4.1,4.2,4.3)全部的逻辑。(只是这里的用户名和密码是用户输入的,不是sp文件中取出来的)5. 绑定注册按钮的点击事件:1.注册按钮的点击事件的逻辑:直接跳转到RegisterActivity界面,无他。6. 实例化显示当前版本号的TextView,并赋值。2. onDestory 方法:0.关闭显示正在登录的对话框1.反注册广播接收器2.停止登陆超时计时器3. handlermessage 方法的处理逻辑:1. 收到msg.what==0时1.关闭显示正在登录的对话框2.吐司显示登录失败4. 广播接收器里面的处理逻辑:1.action== UIDfineAction.ACTION_TCP_LOGIN_RESPONSE:{在登录按钮点击或者当前Activity创建的之后,会发送出去}1. 收到该广播之后,先判断(null==mLoginDialog || !mLoginDialog.isShowing())是否成立,Y 如果成立,就1.获取该广播携带的数据(UIDfineAction.RESULT_KEY, 1),赋值给局部变量result,如果result==0,那么1. 保存"用户名=密码"到sp文件2. 保存用户名到sp文件3. 将.properties文件的信息赋值给一个properties对象,给Config类的静态成员变量赋值4. 如果当前Activity有LoginDialog对象,先置空,然后创建一个,并显示出来。1、 在LoginDialog的构造函数中: 1. 加载UI1. 实例化View2. 给ListView设置数据适配器(===数据源来自Config类中保存的Properties文件中的client_id的值)
                                                                1. 在getView 中,在Item尾部复选框的点击事件中,判断当前item的位置是否在clients.size()的范围内,
                                                                如果在,就将设置当前Item为选中状态反置,并且根据当前Item是否被选中来确定是否给currentSelectClient赋值。
                                                                如果当前Item是选中状态就将当前position+"",赋值给currentSelectClient,否则赋值""给它。
                                                            3. 绑定按钮的点击事件"对话框底部的--OK,立即体验"的点击事件
                                                                点击事件逻辑:
                                                                    1. 判断listview的item是否有被选中过,
                                                                        Y 如果有:
                                                                            1. 将当前系统时间毫秒值赋值给成员变量mTime
                                                                            2. 将sp中sp_CLIENT_ID字段赋值为""
                                                                            3. 开启一个定时器,30秒后发送Handler消息,携带what==0;
                                                                            4. 弹出对话框显示"正在登入账号,请稍等..."
                                                                            5. 发送广播,action= UIDfineAction.ACTION_LOGIN,
                                                                            并携带数据("cliend_id", Config.getClient_id().split(",")[Integer.parseInt(currentSelectClient)]),
                                                                            以及("cliend_pwd", Config.getClient_token().split(",")[Integer.parseInt(currentSelectClient)]),
                                                                            以及("sid", Config.getMain_account()),以及("sid_pwd", Config.getMain_token());
                                                                        N 如果没有选中过Item:
                                                                            1. 将sp中sp_CLIENT_ID字段赋值为""
                                                                            2. 土司显示"选择一个测试用户"

                        2. 否则(result!=0),根据result值的不同->土司显示具体的失败原因。
                    N 如果不成立,就不做任何处理.
            2. action== UIDfineAction.ACTION_TCP_LOGIN_CLIENT_RESPONSE:{在application打开时就创建的Service中的连接失败时的回调,以及连接成功时的回调会发送该action的广播}
                1. 判断mLoginDialog是否还在显示
                    Y 在显示,判断意图对象携带的数据(UIDfineAction.RESULT_KEY, 1)==0?
                        Y ==0
                            1. 土司提醒登录成功
                            2. 过一秒钟,关闭对话框,跳转到AbilityShowActivity界面,关闭当前Activity。
                        N !=0
                            1. 土司提醒登录失败+携带的数据值。
    }
5. AudioActivity{AudioActivity的逻辑:1. onCreate方法的逻辑处理1. 实例化View控件2. 给ListView设置数据,数据来源-->Config类中的Properties中保存的。1. ListView的Item的点击事件:1.通过意图开启新的Activity-->AudioCallActivity,并携带数据("call_client", call_client),以及("call_phone", phone),以及("call_position", phone_position);}
6. AudioCallActivity{AudioCallActivity的逻辑:1. onCreate方法的逻辑处理1. 实例化View控件2. 给View绑定点击事件1.免费电话的点击事件1. 检测网络连接,如果没有网络连接,就结束该方法2. 如果走到这一步,通过意图启动新的界面-->AudioConverseActivity并携带数据("call_client",getIntent().getStringExtra("call_client")),以及("call_type", 1);}
7.AudioConverseActivity{AudioConverseActivity的逻辑:1.onCreate方法的逻辑处理1. 初始化Views1. 实例化xml中定义的view 2. 给相应的View设置开启当前Activity的intent对象携带的数据3. 给相应的View绑定点击事件1. 静音按钮的点击事件的逻辑处理:1. UI做相应的背景切换2. 通过SDK提供的UCSCall.setMicMute(boolean)来反置当前是否静音的状态2. 扬声器按钮的点击事件的逻辑处理:1. UI做相应的背景切换2. 通过SDK提供的UCSCall.setSpeakerphone(boolean)来反置当前是否打开扬声器的状态3. 接通按钮的点击事件的逻辑处理:1. 停止响铃(SDK提供的方法)UCSCall.stopRinging();2. 接听UCSCall.answer("");3. 关闭扬声器4. 挂掉按钮的点击事件的逻辑处理1. 停止响铃2. 挂断3. 1.5秒之后,关闭当前界面5. 结束通话按钮的点击事件的逻辑处理1. 停止响铃2. 关闭扬声器3. 挂掉4. 1.5秒之后,关闭当前界面6. 结束通话(键盘界面中的按钮)的点击逻辑处理:如同5的逻辑7. 打开键盘按钮的点击事件逻辑处理:1.key_layout 显示2.converse_main 隐藏8. 关闭键盘按钮的点击事件的逻辑处理:7取反逻辑9. 各数字键点击的逻辑处理1. 调用SDK提供的UCSCall.sendDTMF(context,str,view)去处理2. 获取系统服务AudioManager3. 获取系统音量最大值4. 获取当前系统音量5. 关闭屏幕触摸音6. 注册广播,接收7个广播:接收的广播的action: UIDfineAction.ACTION_DIAL_STATE&&  UIDfineAction.ACTION_CALL_BACK&&  UIDfineAction.ACTION_ANSWER&&  UIDfineAction.ACTION_CALL_TIME&&  UIDfineAction.ACTION_DIAL_HANGUP&&  UIDfineAction.ACTION_NETWORK_STATE&&  android.intent.action.HEADSET_PLUG   // 插拔耳麦广播7. 获取当前Activity开启时,传递的意图携带的数据,并赋值给成员变量8. 根据意图携带的("inCall", false)的值,来判断当前是来电还是去电,分别做不同的逻辑处理Y,如果为true,说明是来电:1. 如果传递的意图中携带了昵称信息,就在UI中显示昵称,否则显示电话号码2. 打开扬声器3. 开始响铃4. 接听,挂断的View隐藏,结束通话的View显示N,不是true,说明是去电:1. 接听,结束通话View隐藏,挂断View显示2. 进行拨号1. 关闭扬声器2. 打开屏幕触摸音3. 创建一个新的意图对象1. action==UIDfineAction.ACTION_DIAL2. 根据当前Activity的打开意图是否携带UIDfineAction.FROM_NUM_KEY对应的Str如果有携带就将该数据封装到刚创建的意图中3. 根据当前Activity的打开意图是否携带UIDfineAction.TO_NUM_KEY对应的Str如果有携带就将该数据封装到刚创建的意图中4. 根据callType(当前Activity打开意图携带过来的)的不同,再封装两组数据进刚才创建的意图中,并发送该action对应的广播,[action== UIDfineAction.ACTION_DIAL]case 0:// 直拨传入电话号码sendBroadcast(intent.putExtra(UIDfineAction.CALL_PHONE, calledPhone).putExtra("type", calltype));break;case 1:// 免费传入clientidsendBroadcast(intent.putExtra(UIDfineAction.CALL_UID, calledUid).putExtra("type", calltype));break;case 2:// 回拨传入电话号码sendBroadcast(intent.putExtra(UIDfineAction.CALL_PHONE, calledPhone).putExtra("type", calltype));break;case 3:// 视频点对点 传入clientidsendBroadcast(intent.putExtra(UIDfineAction.CALL_UID, calledPhone).putExtra("type", calltype));break;case 5:// 智能拨打 clientid和电话号码同时传入,先选择clientid进行免费拨打,如果对方不在线再选择手机号码进行直拨sendBroadcast(intent.putExtra(UIDfineAction.CALL_UID, calledUid).putExtra(UIDfineAction.CALL_PHONE, calledPhone).putExtra("type", calltype));---->该广播在app打开时创建的广播中有处理!!!3. 根据intent传入的callType的不同,分别在UI上显示"免费电话呼叫中","直拨电话呼叫中"等不同文字2. 广播接收器中的逻辑处理1. action== UIDfineAction.ACTION_DIAL_STATE 1. 根据意图传递的state的值给TextView.converse_information显示不同的文字(多半是错误信息)。2. action== UIDfineAction.ACTION_CALL_BACK1. converse_information.setText("回拨成功");2. 停止响铃(来去电的响铃都停止)3. 1.5秒之后关闭当前界面3. action== UIDfineAction.ACTION_ANSWER1. UI做相应的改变2. 停止响铃3. 关闭扬声器4. 变量open_headset = true;4. action== UIDfineAction.ACTION_DIAL_HANGUP1. 1.5秒之后,关闭当前界面5. action== UIDfineAction.ACTION_CALL_TIME1. 获取intent携带的数据String timer = intent.getStringExtra("timer");2. 将获取的数据赋值给converse_information.setText(timer);6. action== UIDfineAction.ACTION_NETWORK_STATE1. 获取Intent携带的数据("state", -1),并根据该数值在TextView中显示网络状态极好,还是一般还是差等信息。7. action== "android.intent.action.HEADSET_PLUG" //插拔耳麦广播1. 根据当前是否有耳麦插入,如果耳麦插入就关闭扬声器,否则打开。3. onDestory的逻辑处理1.反注册广播2.停止响铃3.如果之前有关闭过屏幕触摸音,现在打开} *******
> 第一条线,也就是语音通话的整个流程差不多就这样子了。不过,由于水平有限,以及无意的疏漏,还是有可能对源码的理解有些偏差与遗漏。不过,大体流程,也就是这样子了。
>
> 简单总结一下语音通话这条线的逻辑,差不多就是> 1. 将必要的数据保存到文件中2. 在需要通知其他界面或者后台做对应操作的时候,通过这边发送广播,那边接收广播的方式进行数据的传递。
>
>这条线的一个重要的类就是`Config`类,这个`Config`类其实算是`java.util.Properties`的一个包装类,所有的核心逻辑就是将数据存入`/config.properties`文件中,以及,从该`.properties`文件中取出对应的数据,在各个需要的UI进行数据展示。>首先,在首次登录的时候,会发一个post请求将登录信息发送到云之讯的服务器端,返回一个json串。然后就调用了`Config.parseConfig(json,context)`的方法,将json中返回的登录信息,帐号信息等存放到了`.properties`文件中,然后后面的操作都是基于这个配置文件的中的数据来的。
2. 给ListView设置数据适配器(<===数据源来自Config类中保存的Properties文件中的client_id的值)
                                                                1. 在getView 中,在Item尾部复选框的点击事件中,判断当前item的位置是否在clients.size()的范围内,
                                                                如果在,就将设置当前Item为选中状态反置,并且根据当前Item是否被选中来确定是否给currentSelectClient赋值。
                                                                如果当前Item是选中状态就将当前position+"",赋值给currentSelectClient,否则赋值""给它。
                                                            3. 绑定按钮的点击事件"对话框底部的--OK,立即体验"的点击事件
                                                                点击事件逻辑:
                                                                    1. 判断listview的item是否有被选中过,
                                                                        Y 如果有:
                                                                            1. 将当前系统时间毫秒值赋值给成员变量mTime
                                                                            2. 将sp中sp_CLIENT_ID字段赋值为""
                                                                            3. 开启一个定时器,30秒后发送Handler消息,携带what==0;
                                                                            4. 弹出对话框显示"正在登入账号,请稍等..."
                                                                            5. 发送广播,action= UIDfineAction.ACTION_LOGIN,
                                                                            并携带数据("cliend_id", Config.getClient_id().split(",")[Integer.parseInt(currentSelectClient)]),
                                                                            以及("cliend_pwd", Config.getClient_token().split(",")[Integer.parseInt(currentSelectClient)]),
                                                                            以及("sid", Config.getMain_account()),以及("sid_pwd", Config.getMain_token());
                                                                        N 如果没有选中过Item:
                                                                            1. 将sp中sp_CLIENT_ID字段赋值为""
                                                                            2. 土司显示"选择一个测试用户"

                        2. 否则(result!=0),根据result值的不同->土司显示具体的失败原因。
                    N 如果不成立,就不做任何处理.
            2. action== UIDfineAction.ACTION_TCP_LOGIN_CLIENT_RESPONSE:{在application打开时就创建的Service中的连接失败时的回调,以及连接成功时的回调会发送该action的广播}
                1. 判断mLoginDialog是否还在显示
                    Y 在显示,判断意图对象携带的数据(UIDfineAction.RESULT_KEY, 1)==0?
                        Y ==0
                            1. 土司提醒登录成功
                            2. 过一秒钟,关闭对话框,跳转到AbilityShowActivity界面,关闭当前Activity。
                        N !=0
                            1. 土司提醒登录失败+携带的数据值。
    }

云之讯官方测试Demo音频版源码阅读(编辑)相关推荐

  1. 云之讯官方测试Demo音频版源码阅读

    由于最近项目中貌似需要做这一块,于是就去读了一下云之讯官方测试Demo的音频版的源码Android音频版. 其实这个Demo并不是什么高大上的代码,也没有很多生涩难懂的代码在里面,相反,读起来还是很轻 ...

  2. 人脸检测颜值软件_AI人脸颜值测颜版下载-百度ai测试颜值人脸识别源码下载v1.0 免费版-西西软件下载...

    百度ai测试颜值人脸识别源码这是由官方百度AI精心打造出来的,这款软件将人脸识别氛围V2和V3两个接口,而且用户使用可以参考相应的文档权限来选择接口类型,让广大用户学习到百度AI人脸识别测颜值相关知识 ...

  3. 智慧党建云平台小程序 v2.4.9+前端(公众号+小程序一体)开源版源码下载安装教程

    智慧党建云平台(vlinke_fdcparty)v2.4.9小程序功能模块,源码带最新微信小程序前端,小程序主程序后端,播播资源网小编测试前后端正常使用!分享的版本是最新标准版模块,模块是目前比官方低 ...

  4. PHP仿金蝶云ERP进销存V8网络多仓版源码

    介绍: PHP仿金蝶云ERP进销存V8网络多仓版源码 功能强大 完善图片上传错误 本系统采用PHP+MYSQL开发,B/S架构,方便随地使用,不管是界面上还是功能上都可以说无可挑剔. 系统特色: 1. ...

  5. php云erp源码下载,PHP仿金蝶云ERP进销存V8网络多仓版源码

    PHP仿金蝶云ERP进销存V8网络多仓版源码 功能强大 完善图片上传错误 本系统采用PHP+MYSQL开发,B/S架构,方便随地使用,不管是界面上还是功能上都可以说无可挑剔. 系统特色 1.扫描枪入库 ...

  6. 阿里api网关接口客户端demo,java实现源码,其他语言可参考

    访问阿里api网关接口客户端demo,java实现源码,其他语言可参考 上一篇文章 <阿里api网关接口创建.发布.授权.调试> 中,介绍了3个典型接口的创建并在阿里控制台调试完成,地址: ...

  7. h5制作 php 开源,PHP源码:2019最新仿易企秀V15.1完整版开源版源码,修复采集功能、新增同行站模板采集等...

    源码说明: 更新功能如下: 新增同行站模板采集 修复模板中心采集方法 修复自定义场景加载LOGO问题 预览H5不在是默认封面加载 可以自定义自己的网站LOGO 安装说明: 把源码包上传到网站根目录 然 ...

  8. 易企秀 伪静态 linux,最新仿易企秀V15.1完整版开源版源码分享,修复采集功能,新增同行站模板采集功能等等...

    源码说明:0 j; j/ T/ g! d* a& [ 易企秀是一款针对移动互联网营销的手机网页DIY制作工具,用户可以编辑手机网页,分享到社交网络,通过报名表单收集潜在客户或其他反馈信息.用户 ...

  9. 羊了个羊游戏h5网页版源码

    羊了个羊游戏h5网页版源码 h5网页版,数据还是官方的,一个小demo. 无后台下载附件源码,上传至服务器访问域名即可 不可商业,不可商业,不可商业 只限交流学习 免广告用道具 下载地址 https: ...

最新文章

  1. linux fio释放内存,linux使用FIO测试磁盘的iops
  2. 决策树算法详解(1)
  3. python真的超过java了吗-Python 的开发效率真的比 Java高吗?
  4. java中字段值重复校验,Java中一些常见的字段校验
  5. RMAN备份filesperset用法
  6. ipv4地址是几位二进制数_几张思维导图,让你清楚的知道ip地址怎么回事?
  7. Serilog 日志框架如何自动删除超过 N 天的日志 ?
  8. 创建一个storageevent事件_谈谈StorageEvent
  9. arcgis api for js入门开发系列十二地图打印(GP服务)
  10. python渲染html页面_python接口自动化29-requests-html支持JavaScript渲染页面
  11. js中while死循环语句_JavaScript循环 - while
  12. 线性基的一些基础模版
  13. 【bzoj2219-数论之神】求解x^a==b(%n)-crt推论-原根-指标-BSGS
  14. DOTA版设计模式——责任链
  15. Excel可视化图表模板,图表控的你快收藏呀!!!
  16. android安卓技能进阶篇
  17. 2022码支付个人免签支付源码+监控APP/实测成功
  18. github 提交消息的emoji表情符号规范
  19. 海洋测绘 知识点 详细
  20. 计算机的第一道安全防线是,网络安全的第一道防线是

热门文章

  1. trac mysql_Ubuntu 8.04下配置项目管理工具Trac
  2. 常见前端面试题及答案
  3. Educoder头歌-Linux vi/vim编辑器
  4. linux ftp主动和被动模式切换命令,Linux iptables配置FTP的主动和被动模式
  5. python 定时给女朋友发QQ邮件
  6. uni-app 上传图片到七牛云
  7. 全栈项目【尚医通】预约挂号系统项目介绍
  8. SSL数字证书是什么?
  9. 使用swoole来加速你的laravel应用
  10. JESD204标准概述