Cordova+Asp.net Mvc+GIS跨平台移动应用开发实战1-系统初步搭建(附演示,apk,全部源码)...

 1.前言

        身处在移动互联网的今天,移动应用开发炙手可热,身为程序猿的我们怎么能错过开发一款我们自己的APP.本人算是一个基于.net的GIS开发入门者(马上就大四啦), 暑假在学校参加GIS比赛有大把的时间,利用最近这两天自己写了一个跨平台移动APP。功能比较简单,以后我会慢慢完善的。为什么要跨平台呢?大学期间主要学.net,而微软不太给力啦,WP开发基本上已近死啦 .而重新学习Android开发比较吃力费时。由于对HTML、JavaScript与CSS 等 Web 技术开发有所了解,最终选择使用Cordova来做跨平台移动应用。本次使用的技术主要有Cordova,Asp.net Mvc+EF,jquery mobile,bootstorap,百度地图Javascript API等。功能

2.功能     

目前主要是实现基于位置的拍照,存储,地图的可视化显示等,使用户更好的管理自己的照片以及照片背后的空间地理位置和故事。大家可以下载apk试用一下啊。

1.登录

2.注册

3.主页

   a.定位

   b.照片位置点的地图显示,以及属性窗口

   c.拍照上传

   d.照片详情展示

3.演示

      

 安装包获取                                                                      权限获取                                           安装完成

            

         GISAPP安装完成                                                      启动屏                                                    登录

            

                   注册                                                           主页                                                        GPS获权

         

                 位置显示                                                查看已有照片信息                                                拍照页

          

                       启动摄像头                                     提交照片信息                                                      提交的信息反馈

          

                 照片详情                                                       照片详情                                               待实现功能

4.实现

1.Cordova简介

Cordova是贡献给Apache后的开源项目,是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎。

Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等。

Cordova还提供了一组统一的JavaScript类库,以及为这些类库所用的设备相关的原生后台代码。

Cordova支持如下移动操作系统:iOS, Android,ubuntu phone os, Blackberry, Windows Phone, Palm WebOS, Bada 和 Symbian。

具体介绍可以参考官网:http://cordova.apache.org/

2.Cordova平台环境配置

需要安装的东西如下(android为例)

1.配置JDK环境
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
安装jdk-8u5-windows-x64.exe,
配置环境变量
JAVA_HOME = C:\Program Files\Java\jdk1.8.0_05
Path += %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
CLASSPATH += %JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
2.配置android-sdk环境
http://developer.android.com/design/downloads/index.html
解压android-sdk.rar到D:\Android\
配置环境变量
ASDK_HOME = D:\Android\sdk
Path += %ASDK_HOME%\platform-tools;%ASDK_HOME%\tools;

3.配置Node环境
http://nodejs.org/download/
安装node-v0.10.29-x64.msi
配置环境变量
NODE_HOME = C:\Program Files\Nodejs\
Path += %NODE_HOME%;

4.配置Cordova环境

在cmd中运行npm install -g cordova(在线安装)

3.数据库设计

一个用户表,一个照片表。

值得注意的是字段Location(位置)我使用的是Geometry类型存储的,这是.net 4.5后新支持的字段类型,对应sqlserver中的geometry类型,以后我们专门写博客讲这个东西的。

4.页面构建以及服务端通信

登录注册使用bootstorap做得响应式布局以及后台验证实现

a.页面搭建(登录为例)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>MyHybirdApp</title>
        <link href="assets/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
        <link href="assets/css/style.css" rel="stylesheet" />
    </head>
<body>
    <!-- 表单区域 -->
    <form id="form_login" class="form-main" method="get" autocomplete="off">
        <h2>登  录</h2>
        <hr />
        <div class="avator">
            <img id="myavator" src="assets/img/avatar.jpg" />
        </div>
        <div class="message-box"></div>
                <!--.sr-only 可以用于隐藏元素-->
        <label for="username" class="sr-only">Username</label>
        <input id="username" type="text" class="form-control input-lg input-group-top" placeholder="请输入用户名" required autofocus>
        <label for="password" class="sr-only">Password</label>
        <input id="password" type="password" class="form-control input-lg input-group-bottom" placeholder="请输入密码" required>
        <div class="checkbox">
            <input id="remember" type="checkbox" value="remember-me" checked/>
            <label for="remember">记 住 我</label>
            <a class="link" href="register.html">注 册</a>
        </div>
        <button id="btn_login" class="btn btn-lg btn-info btn-block">登  录</button>
    </form>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>MyHybirdApp</title>
        <link href="assets/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
        <link href="assets/css/style.css" rel="stylesheet" />
    </head>
<body>
    <!-- 表单区域 -->
    <form id="form_login" class="form-main" method="get" autocomplete="off">
        <h2>登  录</h2>
        <hr />
        <div class="avator">
            <img id="myavator" src="assets/img/avatar.jpg" />
        </div>
        <div class="message-box"></div>
                <!--.sr-only 可以用于隐藏元素-->
        <label for="username" class="sr-only">Username</label>
        <input id="username" type="text" class="form-control input-lg input-group-top" placeholder="请输入用户名" required autofocus>
        <label for="password" class="sr-only">Password</label>
        <input id="password" type="password" class="form-control input-lg input-group-bottom" placeholder="请输入密码" required>
        <div class="checkbox">
            <input id="remember" type="checkbox" value="remember-me" checked/>
            <label for="remember">记 住 我</label>
            <a class="link" href="register.html">注 册</a>
        </div>
        <button id="btn_login" class="btn btn-lg btn-info btn-block">登  录</button>
    </form>
</body>
</html>
View Code

b.Ajax表单提交

我们知道在传统PC 浏览器端中,ajax请求受限于XMLHttpRequest无法进行跨域请求,我们可能需要借助JSONP一类的帮手帮我们解决,而在Cordova生成的Hybird App中不需要考虑这个问题。在上面的代码中,get请求访问的是一个位于远端服务器中的一个服务(可以是ashx一般处理程序,也可以是一个MVC应用的action)。

   <script src="assets/lib/jquery/jquery-1.11.0.min.js"></script>
    <script>
        $(function () {
            $('#btn_login').click(function () {
                var username = $.trim($("#username").val());
                var password = $.trim($("#password").val());
                if (username.length < 1) {
                    alert("请输入用户名");
                    return false;
                }
                if (password.length < 1) {
                    alert("请输入密码");
                    return false;
                }
                $.get('http://localhost:62383/UserInfo/Login?username=' + username + '&password=' + password + '', {}, function (data) {
                    if (data.Message == "success") {
                        window.location.href = "APP.html?username=" + data.UserName + "&id=" + data.Id;
                    } else {
                        alert(data.Message);
                    }
                });
                //click事件中加return false来阻止冒泡
                return false;
            });
        });
    </script>
View Code

注意:登录成功后回调函数中通过设置url进行登录信息保存与传递。window.location.href = "APP.html?username=" + data.UserName + "&id=" + data.Id;

c.后台验证

  [HttpGet]
        public ActionResult Login(string username, string password)
        {
            GISAppDBEntities1 db = new GISAppDBEntities1();
            string message;
               if (string.IsNullOrEmpty(username))
            {
               message = "请输入用户名";
               return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
            }
            if (string.IsNullOrEmpty(password))
            {
                 message = "请输入密码";
                 return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
            }
             //密码加密后对照
            password = MD5Helper.EncryptString(password);
            UserInfo userInfo =
                db.UserInfo.Where(u => u.UserName == username && u.PassWord == password).FirstOrDefault();

            if (userInfo == null)
            {
                message = "登录失败用户名或密码错误";
                return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
            }
            return Json(new { Message = "success", UserName = username, Id = userInfo.UId}, JsonRequestBehavior.AllowGet);
        }
View Code

主页jquery mobile+百度地图Javascript API

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <title>JQueryApp 01</title>
    <!--网页不允许放大缩小-->
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <link rel="stylesheet" href="assets/lib/mobile/themes/my-custom-theme.min.css" />
    <link rel="stylesheet" href="assets/lib/mobile/themes/jquery.mobile.icons.min.css" />
    <link href="assets/lib/mobile/jquery.mobile.structure-1.4.2.min.css" rel="stylesheet" />
    <style>
        #allmap {
            position: absolute;
            background-color: #EEEEDD;
            height: 87%;
            width: 100%;
            padding: 0px;
            z-index: 0;
            left: 0px;
        }
        #wimg {
            width: 100%;
            position: absolute;
            bottom: 120px;
            z-index: 99;
            text-align: center; 
        }
        #Warning {
            width: 120px;
            height:120px
        }
        .ui-btn {
            padding-bottom: 2px; 
        }
    </style>
</head>
<body>
    <!--data-role属性就是JQM中控件的概念-->
    <div data-role="page" data-theme="a">
        <div data-fullscreen="false" data-position="fixed" data-role="header">
            <h1 id="user"></h1>
        </div>
        <div data-role="ui-content" id="mapcontent">
            <div id="allmap">
            </div>
            <div  id="wimg">
                <img src="assets/lib/mobile/images/yujing.png" id="Warning"/>
            </div>
        </div>
        <div  data-position="fixed" data-role="footer" data-fullscreen="false">
        <div data-role="navbar">
            <ul class="ui-grid-c" >
                    <li class="ui-block-a"><a  href="#" data-icon="location" data-iconpos="top" class="ui-btn-active" id="app">定位</a></li>
                    <li class="ui-block-b"><a data-ajax="false" href="#" data-icon="heart" data-iconpos="top" id="main">主页</a></li>
                    <li class="ui-block-c"><a data-ajax="false" href="#" data-icon="comment" data-iconpos="top" id="news">资讯</a></li>
                    <li class="ui-block-d"><a data-ajax="false" href="#" data-icon="gear" data-iconpos="top" id="setting">设置</a></li>
                </ul>
            </div>
        </div>
    </div>
</body>
</html>
<script src="assets/lib/jquery/jquery-1.11.0.js"></script>
<script src="assets/lib/mobile/jquery.mobile-1.4.2.js"></script>
       <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=jSVkiBOGSsNh69VzlhaHReHVuZvWvzNA"></script>
<script type="text/javascript">
    //URL截取
    var queryString = window.location.search.substr(1);
    var qureyArr = {};
    var tempArr = queryString.split('&');
    for (var i = 0; i < tempArr.length; i++) {
        var kv = tempArr[i].split('=');
        if (kv.length == 2) {
            qureyArr[kv[0]] = kv[1];

        } else if (kv.length == 1) {
            qureyArr[kv[0]] = "";
        }
    }
    var id = qureyArr.id;
    var username = decodeURI(qureyArr.username);
    //将用户信息传到其他href设置
    $("#main").attr("href", "main.html?id=" + id + "&username="+username);
    $("#news").attr("href", "news.html?id=" + id + "&username=" + username);
    $("#setting").attr("href", "setting.html?id=" + id + "&username=" + username);
    $("#user").text(username+" の 相 册");
    // 百度地图API功能
    var map = new BMap.Map("allmap");
    //纬度
    var lat;
    //经度
    var lng;
    //地址
    var address ;
    map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
    // 添加带有定位的导航控件
    var navigationControl = new BMap.NavigationControl({
        // 靠左上角位置
        anchor: BMAP_ANCHOR_TOP_LEFT,
        // LARGE类型
        type: BMAP_NAVIGATION_CONTROL_LARGE,
        // 启用显示定位
        enableGeolocation: true
    });
    var top_left_control = new BMap.ScaleControl({ anchor: BMAP_ANCHOR_TOP_LEFT });
    map.addControl(top_left_control);
    map.addControl(navigationControl);
    // 添加定位控件
    var geolocationControl = new BMap.GeolocationControl();
    geolocationControl.addEventListener("locationSuccess", function (e) {
        // 定位成功事件
        lat = e.point.lat;
        lng = e.point.lng;
        address += e.addressComponent.province;
        address += e.addressComponent.city;
        address += e.addressComponent.district;
        address += e.addressComponent.street;
        address += e.addressComponent.streetNumber;
        alert("当前定位地址为:" + address);
    });
    geolocationControl.addEventListener("locationError", function (e) {
        // 定位失败事件
        alert(e.message);
    });
    map.addControl(geolocationControl);
    $(function () {
        var photos;
        //加载点
        $.post("http://localhost:62383/photo/getphoto", { id: id }, function (data) {
            photos = data.photos;
            var x = photos.length;
            var myIcon = new BMap.Icon("assets/img/1432101726.png", new BMap.Size(32, 46));
            for (var i = 0; i < photos.length; i++) {
                var marker = new BMap.Marker(new BMap.Point(photos[i].Lng, photos[i].Lat), { icon: myIcon });  // 创建标注
                var content = photos[i].Title + "</br>" + photos[i].Address + "</br>" + photos[i].CreateDate + "</br>" + photos[i].Url;
                map.addOverlay(marker);               // 将标注添加到地图中
                addClickHandler(content, marker);
                if (i == 0) {
                    //默认缩放至第一点
                    map.centerAndZoom(new BMap.Point(photos[i].Lng, photos[i].Lat), 15);
                }
            }
            var opts = {
                width: 250,     // 信息窗口宽度
                height: 150,     // 信息窗口高度
                title: "图片窗口", // 信息窗口标题
                enableMessage: true//设置允许信息窗发送短息
            };
            function addClickHandler(content, marker) {
                marker.addEventListener("click", function (e) {
                    openInfo(content, e);
                }
                );
            }
            function openInfo(content, e) {
                var p = e.target;
                var point = new BMap.Point(p.getPosition().lng, p.getPosition().lat);
                var infoWindow = new BMap.InfoWindow(content, opts);  // 创建信息窗口对象 
                map.openInfoWindow(infoWindow, point); //开启信息窗口
            }
        });
        $("#Warning").click(function myfunction() {
            if (lat == null || lng == null) {
                alert("请先进行定位操作");
                return false;
            }
            window.location.href = "edit.html?lat=" + lat + "&lng=" + lng + "&address=" + address + "&id=" + id + "&username=" + username;
            return false;
        });
    });
       </script>
View Code

5.调用手机硬件进行拍照

摄像头的调用(只能使用手机调试,web端不能调试)

a.页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta content="width=device-width, initial-scale=1" name="viewport">
        <link rel="stylesheet" href="assets/lib/mobile/themes/my-custom-theme.min.css" />
        <link rel="stylesheet" href="assets/lib/mobile/themes/jquery.mobile.icons.min.css" />
        <link href="assets/lib/mobile/jquery.mobile.structure-1.4.2.min.css" rel="stylesheet" />
        <link href="assets/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
        <title>发布照片</title>
        <style>
            #photobg { width: 150px }

            #label { margin-top: 10px }

            #content { height: 200px !important }
        </style>
    </head>
    <body>
        
        <div data-role="page" data-theme="a">
            <div data-fullscreen="false" data-position="fixed" data-role="header">
                <h1>发布照片</h1>
            </div>
            <div class="container">
                <div class="row" style="margin-top: 20px">
                    <div class="col-xs-4" id="phototest">
                        <br />  <br /><p class="text-center text-muted">照片</p>
                    </div>
                    <div class="col-xs-8">
                        <img src="assets/img/photobg.png" class="img-thumbnail" id="photobg"/>
                    </div>
                </div>
                <hr />
                <div class="row">
                    <div class="form-group">
                        <label for="title" class="col-xs-2 control-label text-center text-muted" id="label">标题</label>
                        <div class="col-xs-10">
                            <input type="text" class="form-control" id="title" name="title" placeholder="请输入标题"/>
                        </div>
                    </div>
                </div>
                <div class="row"><div class="form-group">
                                     <label for="content" class="col-xs-2 control-label text-center text-muted" id="label1">描述</label>
                                     <div class="col-xs-10">
                                         <textarea  class="form-control" id="content" rows="15" name="content" placeholder="请输入详细描述" ></textarea>
                                     </div>
                                 </div></div>
                
                <hr />
                <div class="row" style="text-align: center">
                    <button  class="btn" style="background: #449d44; color: #fff; width: 30%;" id="btn">提交</button>
                </div>
            </div>
        </div>
    </body>
    <script src="assets/lib/jquery/jquery-1.11.0.min.js"></script>
    <script src="assets/lib/mobile/jquery.mobile-1.4.2.js"></script>
    <script src="cordova.js"></script>
    <script>
        $(function () {
            //存储图片DATA_URL
            var photobg;
            //调用拍照插件
            $('#photobg').click(function () {
                navigator.camera.getPicture(onSuccess, onFail, {
                    quality: 50,
                    destinationType: Camera.DestinationType.DATA_URL
                });

                function onSuccess(imageData) {
                    photobg = imageData;
                    var image = document.getElementById('photobg');
                    image.src = "data:image/jpeg;base64," + imageData;
                }

                function onFail(message) {
                    alert('Failed because: ' + message);
                }
            });
            //URL截取
            var queryString = window.location.search.substr(1);
            var qureyArr = {};
            var tempArr = queryString.split('&');
            for (var i = 0; i < tempArr.length; i++) {
                var kv = tempArr[i].split('=');
                if (kv.length == 2) {
                    qureyArr[kv[0]] = kv[1];

                } else if (kv.length == 1) {
                    qureyArr[kv[0]] = "";
                }
            }
            var username = decodeURI(qureyArr.username);
            $("#btn").click(function() {
                var title = $.trim($("#title").val());
                var content = $.trim($("#content").val());
                if (title.length < 1) {
                    alert("请输入标题");
                    return false;
                }
                $.post("http://localhost:62383/Photo/Add", {
                    photobg: photobg,
                    title: title,
                    id:qureyArr.id,
                    content: content,
                    lat: qureyArr.lat,
                    lng: qureyArr.lng,
                    address: qureyArr.address
                }, function(data) {
                    if (data.Message == "success") {
                        window.location.href = "APP.html?username=" + username + "&id=" + qureyArr.id;
                    } else {
                        alert(data.Message);
                    }
                });
            });
        });
    </script>
</html>
View Code

其中cordova.js就是cordova进行手机底层硬件访问的js

    destinationType: Camera.DestinationType.DATA_URL :这段是设置照片的返回类型为dataurl,为下面图片上传做准备

b.后台提交

/// <summary>
         /// 添加照片
         /// </summary>
         /// <param name="lat">纬度</param>
         /// <param name="lng">精度</param>
         /// <param name="address">地址</param>
         /// <param name="title">标题</param>
         /// <param name="content">描述</param>
         /// <param name="photobg">上传图片dataurl</param>
         /// <param name="id">用户编号</param>
         /// <returns></returns>
        public ActionResult Add(string lat, string lng, string address, string title, string content, string photobg,int id)
        {
           //byte[] arr = Convert.FromBase64String(photobg);
           //using (MemoryStream ms = new MemoryStream(arr))
           // {
           //     Bitmap bmp = new Bitmap(ms);
           //     bmp.Save("/images/" + DateTime.Now.ToFileTime() + ".jpg");
           // }
            GISAppDBEntities1 db = new GISAppDBEntities1();
            //url解码
           address= HttpUtility.UrlDecode(address);
           if (address.Contains("undefined"))
           {
               address = address.Replace("undefined","");
           }
           string point = "POINT(" + lng + " " + lat + ")";
            Photo photo = new Photo();
            photo.Address = address;
            photo.Picture = "";
            photo.CreateDate = DateTime.Now;
            photo.Content = content;
            photo.Title = title;
            photo.UserInfoUId = id;
            photo.Location = DbGeometry.PointFromText(point, 4326);
            db.Photo.Add(photo);
            if (db.SaveChanges() != 1)
            {
                return Json(new { Message = "服务器错误" }, JsonRequestBehavior.AllowGet);
            }
            return Json(new { Message = "success" }, JsonRequestBehavior.AllowGet);
        }
View Code

图片的上传

1.我们知道对与form表单的提交,pc之间提交照片要使用<input type=”file”/>进行提交,但是我们想在手机上提交照片怎么办呢?下面有两种方式。

a.将图片通过base64编码生成dataurl进行传输,然后在后台解码生成图片

b.cordova插件cordova-plugin-file-transfer 进行异步提交

为了简单我直接通过base64编码生成dataurl进行传输,这种方法,

其他功能实现请查看我的源码,这里就不过多介绍啦。

5.Cordova项目构建与打包示例

1.创建项目

在要建立项目的文件加下shift+右键,点击在此处打开命令窗口,在控制台中输入

2.创建android平台

 

3.添加访问硬件的插件

4.项目导入到根目录www文件夹里面

将我们开发的web网页以及依赖的资源(图片、css、js等)拷贝到此目录下

5.配置根目录下的config.xml

设置APP图标和启动屏

<?xml version='1.0' encoding='utf-8'?>
<widget id="cn.sharegis.app" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>GISAPP</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>
    <content src="login.html" />
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <platform name="android">
        <allow-intent href="market:*" />
         <allow-intent href="market:*" />
        <icon src="www/gps.png" density="ldpi" />
        <icon src="www/gps.png" density="mdpi" />
        <icon src="www/gps.png" density="hdpi" />
        <icon src="www/gps.png" density="xhdpi" />
        <splash src="www/screen.png" density="land-hdpi" />
        <splash src="www/screen.png" density="land-ldpi" />
        <splash src="www/screen.png" density="land-mdpi" />
        <splash src="www/screen.png" density="land-xhdpi" />
        
        <splash src="www/screen.png" density="port-hdpi" />
        <splash src="www/screen.png" density="port-ldpi" />
        <splash src="www/screen.png" density="port-mdpi" />
        <splash src="www/screen.png" density="land-xhdpi" />
    </platform>
    <preference name="SplashScreenDelay" value="2000" />
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
    </platform>
</widget>
View Code

6.编译

 

6.注意事项

1.你一但选择使用cordova插件来进行操作的话,你在电脑上就不可以调试啦,必须手机操作。

2.手机调试时一定要将手机通过电脑发出的WiFi进行测试,保证手机与后台服务通畅。我自己是使用的一台阿里云服务器,不需要考虑上述通信问题.

3.你在web开发时url可以不注意大小写,但是cordova打包是区分大小写的,例如index.html写成Index.html就会出现异常。

4.手机的真机测试比较慢,所以尽量将逻辑处理测试通过再打打包.节约时间。

7.总结

  本次主要实现了登录注册以及基于GIS的照片管理,实现的功能比较简单。你可下载一下APP试用一下,目前只有android版本,其他平台有兴趣的话可以自己打包。全部源码链接在下面,如果有问题的可以互相交流,不懂得地方可以私信我。后面我还会添加一些新的功能,如果喜欢可以关注一下我。

这个系列未完,待续。。。。。。。。。。。。。。。。。。。。。,期待您的关注

 全部源码:http://pan.baidu.com/s/1c2x9Q7Y

测试APP for android下载:http://pan.baidu.com/s/1c2wTSbe

作者:ATtuing

出处:http://www.cnblogs.com/ATtuing

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/ATtuing/p/5703705.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值