关闭

ionic开发篇之踩坑集

标签: ionicapi调试
3932人阅读 评论(2) 收藏 举报
分类:

一、API篇

1.接口无法访问

百度地图、自定义API无法访问,远程调试结果显示404
原因是cordova 5.x的版本增加了“Content-Security-Policy”用于解决安全访问的问题。默认情况下,只能访问本机资源。

解决方法:
1.添加白名单插件,在项目目录下执行

ionic plugin add cordova-plugin-whitelist

2.在index.html头部增加

<meta http-equiv="Content-Security-Policy"
      content="script-src * 'unsafe-eval'; connect-src * 'unsafe-eval'; 
object-src 'self'; style-src * 'unsafe-inline'; img-src *" >

2.无法跨域访问

服务端设置(PHP)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials:true');

3.POST请求提交自动变成Options请求

当我们使用浏览器调试的时候,发现POST请求会自动变成Options请求,然后调用任意接口都提示不能跨域访问,即使服务端已经设置允许跨域访问。

解决方法:

.config(function ( $stateProvider, $urlRouterProvider, $ionicConfigProvider, $httpProvider) {
    // Use x-www-form-urlencoded Content-Type
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
    }

这个问题只出现在浏览器调试中,实际在手机里运行不需要这个配置。

4. ionic 里使用 iframe 可能遇到的问题

无法访问外部url的问题–两个步骤解决:
iframe的src属性用ng-src属性替代,并指明绑定对象: ng-src=”{{targetUrl}}”
在controller里,调用sce:scope.targetUrl = $sce.trustAsResourceUrl(url)

高度无法最大化的问题–两个步骤解决:
ion-content 属性里添加 scroll=”true” overflow-scroll=”true”,参考
iframe content scroll issue #1151

iframe的style里添加 min-height: 100%,参考
Fill content container

Ionic与第三方的Wap网页交互

采用Windows.Open的方法,打开一个浏览器,不带地址栏,全屏的窗口,显示第三方的WebApp页面。
代码如下:

// event类型有以下几种类型
// loadstart - 开始加载
// loadstop - 完成加载
// loaderror - 加载出错
// exit - 窗口退出
var ref = window.open(encodeURI(url), '_blank','location=no');
 ref.addEventListener('loadstart', function(event) {
     if (event.url.match("mobile/close")) {
         ref.close();
     }
 }); 

当浏览器内的url地址包含 mobile/close页面的时候,就会关闭当前的浏览器。
具体可以参考
http://cordova.apache.org/docs/en/3.0.0/cordova/inappbrowser/inappbrowser.html

二、调试篇

1.本地调试

电脑上本地调试,用ionic serve即可在浏览器中调试

2.远程调试

1.在手机上运行debug版软件,在电脑上调试程序
2.在启动手机上的APP后,在谷歌浏览器(其实360也行)上输入chrome://inspect/#devices,可以进入调试界面(如果出不来,请翻墙)
这里写图片描述
3.单击inspect,可以进入当前显示的页面调试,调试方法和和在浏览器上一致。

远程调试可以快速定位,在浏览器上没有发现的问题,方便调试手机API接口

三、应用篇

1.导航置底设置

好不容易按教程一步步建立了tabs样例工程,却发现安卓机上这个tab导航在顶部,浏览器和ios这个导航在顶部。
解决方案:
在app.js里添加以下代码

.config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
    $ionicConfigProvider.platform.ios.tabs.style('standard');
    $ionicConfigProvider.platform.ios.tabs.position('bottom');
    $ionicConfigProvider.platform.android.tabs.style('standard');
    $ionicConfigProvider.platform.android.tabs.position('bottom');
    $ionicConfigProvider.platform.ios.navBar.alignTitle('center');
    $ionicConfigProvider.platform.android.navBar.alignTitle('center');
    $ionicConfigProvider.platform.ios.backButton.previousTitleText('').icon('ion-ios-arrow-thin-left');
    $ionicConfigProvider.platform.android.backButton.previousTitleText('').icon('ion-android-arrow-back');
    $ionicConfigProvider.platform.ios.views.transition('ios');
    $ionicConfigProvider.platform.android.views.transition('android');

2.百度地图开发

坑1:使用了插件angular-BMap

使用了插件angular-BMap

这个插件功能并不完善,好多功能都没有,如果要使用需要继续开发(如果你有时间,有兴趣,有能力可以fork后继续开发)

坑2:使用了百度地图实例代码,地图不显示

var map = new BMap.Map("container");          // 创建地图实例  
var point = new BMap.Point(116.404, 39.915);  // 创建点坐标  
map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别  

其实只是在模拟手机的浏览器下不显示,在浏览器上不要选择任何手机型号,就能显示,而实际我在自己的手机上build后,也是能正常显示的。具体原因没有深究,如果有知道的朋友欢迎来信。

坑3:GPS位置偏移

使用$cordovaGeolocation.getCurrentPosition()获得的坐标,在百度地图上位置偏移。原因是GPS坐标和百度地图坐标并不是完全对应的,需要使用百度地图提供的GPS坐标转换接口进行转换

 function posToAddrByBaidu(lat, long){

        var Ak = 'yourAK'; //你应用的AK

        var getUrl = 'http://api.map.baidu.com/geocoder/v2/?'+ 'ak=' + Ak +'&location='
            +lat+ ',' + long + '&output=json&pois=0';

        $http.get(getUrl)
            .success(function (data) {
                if (data['status'] == '0') {
                    $scope.appeal.location = data.result.formatted_address;

                } else {
                    return '定位失败';

                }

            }).error(function () {
                alert("网络问题");
            });

    }

坑4 infowindow里面的a链接只能跳转一次

BMap中创建的infowindow,如果里面带有a链接,第一次跳转后,第二次进去就无法跳转了。这个问题目前不知道怎么解决,如果有人知道请告诉我,谢谢。

四、常见错误

1. 编译错误

a. Execution failed for task ‘:app:mergeDebugResources’ OR Execution failed for task ‘:Application:processDebugResources’

> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Users\admin\AppData\Local\Android\sdk\build-tools\23.0.3\aapt.exe'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

Error: Error code 1 for command: cmd with args: /s,/c,"D:\myApp\platforms\android\gradlew cdvBuildDebug -b D:\myApp\platforms\android\build.gradle -Dorg.gradle.daemon=true -Pandroid.useDeprecatedNdk=true"

检查一下,看看是不是哪里的资源文件命名不规范,文件名称不规范就可能导致该问题.
或者执行以下命令:

C:\>D:\myApp\platforms\android\gradlew cdvBuildDebug -b D:\myApp\platforms\android\build.gradle -D org.gradle.daemon=true -Pandroid.useDeprecatedNdk=true" --info --debug > d:\debug.info

然后从d:\debug.info文件中查找详细的错误信息。

2.ionic build android 没有反应

检首次Build的时候 android平台,会安装gradle工具,但是因为网络的问题,很可能安装的非常的慢到无法忍受。那么很有可能是因为你的Gradle的工具会去下载platforms/android/cordova和CordovaLib的maven的库,这个时候需要修改build.gradle文件的repositories库中,mavenCentral()修改成为阿里云的库

    repositories {
        flatDir {
            dirs 'libs'
        }
        //mavenCentral()
        maven { url "http://maven.aliyun.com/nexus/content/groups/public" }
    }

常识与技巧篇

  1. list 有延迟,可以在ion-content处使用 overflow-scroll=”true”尝试
  2. 上用ng-click上是没效果的
  3. 快捷修改背景色style=”background-color: #212326;”
  4. 能用ng-if就用ng-if,ng-if的效率比ng-show和ng-hide高
  5. 直接在ion-list中的ion-item中并不能触发ng-click事件,可以在item中的元素上再套一层div
  6. 可以用ng-class=”{‘important’: post.important}”配合css 根据列表元素显示不同的效果
  7. 获取日期用filtervarpostdate=filter(‘date’)(date, ‘yyyy-MM-dd HH:mm:ss’);
  8. 列表中的元素不能写成 id : 4,应写成 id : “4”,注意在创建id变量的时候也需要转成string,如:

    var id = InfoListService.getListLength()+1+"";

    1. 使用loglog,log而不是console.log呢?可以看看这个
    2. 在安卓上的体验比较差,动画有延迟?可以试试ionic集成的crosswalk
    3. controllers和services 的文件名可能会重合,但是他们意义差不多,可以将controllers中的文件名小写,对应的services中的文件名大写进行区分,或者加后缀xxxControler,xxxService
    4. 安装cordova插件的时候用ionic plugin add …的方式添加,这样会在package.json中添加这个插件的条目,如果有人clone了你的项目想在本地运行,可以用ionic state restore它会根据cordovaPlugins条目安装对应的插件。如果直接用cordova plugin add 安装则不会更新package.json。
    5. 上传base64编码的时候如果提示413错误,是因为文件过大导致的,可以在nodejs中设置bodyparser的文件限制:
var bodyParser = require('body-parser');
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
  1. img 中 base64编码的图片无法显示?在源码中发现angular添加了unsafe标签?需要在白名单中添加data:image
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|content|file|assets-library):|data:image\//);
  1. 有时候pm2运行有问题,重启一下即可

Q&A篇

Q: 在 iOS 下使用 cordova-plugin-file-transfer 下载中文名文件失败,提示 Could not create target file
A: encodeURI(“包含霸气的中文文件名的 URI”)

Q: 应用需要存储较大量数据,原始格式是 json ,存 sqlite 数据库嫌麻烦。
A: lokiJS ,类 mongodb 的 js 内存数据库,配合为 ionic 打造的插件做持久化存储。

Q: 不同 Android 手机上出现字体错位之类的奇怪问题。
A: 使用 Crosswalk 消除不同安卓机上 WebView 的差别,顺便还能提升应用性能。

Q: 在实机上使用 livereload 功能时出现空白、连接失败等情况。
A: 实机上的 livereload 本质是用手机访问电脑上的网站,检查手机和电脑之间的网络连接是否通畅。

Q: gitignore 默认排除了 plugins 文件夹,团队其他人 clone 了项目后缺少插件,一个一个装太麻烦。
A: ionic platform add/remove xxx 以及 ionic plugin add/remove xxx 的时候,Ionic CLI 都在 package.json 中保存了项目的状态。clone 完后可以使用 ionic state restore 命令快速恢复

Q: 在哪里查看 Ionic 带的所有图标?
A: http://ionicons.com

Q: 在 ionic platform add xxx 时卡住
A: 挂 VPN ,或者丢着睡一觉(不确定是不是网络原因,就遇过两次没深究)

Q: tel:xxxxx sms:xxxxxx mailto:xxxxxx geo:xxxxxx 一类的链接不能唤起其他应用。
A: 在 config.xml 中加入:

<access origin="*"/>
<access origin="tel:*" launch-external="yes"/>
<access origin="sms:*" launch-external="yes"/>
<access origin="mailto:*" launch-external="yes"/>
<access origin="geo:*" launch-external="yes"/>

Q: 跟上 Q 一样,加了还 TM 不行!
A: 再在 config.xml 中加入:

<allow-intent href="tel:*"/>
<allow-intent href="sms:*"/>
<allow-intent href="mailto:*"/>
<allow-intent href="geo:*"/>

Q: Android 中调用其他应用打开 applicationDirectory 下的文件时提示路径不存在, iOS 可以。
A: 两个系统策略不一样, Android 中有这个需求简单的办法是参考该页中的 Android 文件系统布局,把文件从 Private 目录复制到 Public 目录下再做操作。

Q: 对 Android 进行远程调试。
A: 打开 Chrome ,地址栏输入 chrome://inspect

Q: 对 iOS 进行远程调试
A: 打开 Safari -> 开发 -> 手机名 -> 应用名

Q: Ionic 的 Modal 是什么鬼?不能给它设定状态么?!
A: 超级弱逼的模态框,因为 uirouter 的限制,给它转状态非常不方便。确定只需要一个页面就能完成的操作才用他。下一 Q 提供个解决办法。

Q: 替代 Modal 的方案
A: 在 $state.go 前记录下当前的 view ,然后禁止下一个 view 记录 backView ,就不会显示后退按钮( Android 硬件后退也不行 )。在需要关闭时,后来加入导航栈的任意 view 中设置 backView 为记录下来的 view ,然后 back 。

// go 的时候
var backHistoryId = $ionicHistory.currentHistoryId();
var backViewId = $ionicHistory.currentView().viewId;
$ionicHistory.nextViewOptions({
  disableBack: true,
  disableAnimate: true
});
$state.go('my-awesome-modal', {backViewId: backViewId});

// back 的时候
var backHistoryId = $ionicHistory.currentHistoryId();
var backView = $ionicHistory.viewHistory().histories[backHistoryId].stack.filter(function (v) {
  return v.stateId === $stateParams.backViewId;
})[0];
$ionicHistory.backView(backView);
$ionicHistory.goBack();

Q: ionic serve 或在实机调试时开启了 livereload 功能时的跨域问题
A:道理还是因为这两种状态下, APP 实际是在访问电脑上的一个网站,任何指向其他地方的链接都是跨域。实机不开 livereload 则不存在这个问题。
简单的方法就是用实机调试且不开 livereload 。
复杂点的比如设置 Ionic 自带的代理服务器,参考链接。需要详细了解这个问题也可以看一遍。

Q: 如何在某个界面中去掉导航栏?
A: 如果某个界面上不想要导航栏,可以简单地在最顶端的标签中添加hide-nav-bar=”true”

如何在ionic中加载本地图片?
A: 对于css文件夹中的样式文件中如果要调用本地的图片的话,从该css文件所在的文件夹开始算,例如www/css/style.css要加../,否则在浏览器中可以正常显示,在设备上不行,结构如下所示:

.login-page {
  background:url(../img/signup_bg.png);
  background-size: cover;
  background-repeat: no-repeat;
}

但是对于在页面中定义的图片路径,从www路径开始算,否则浏览器中可显示,但设备上不行,img文件夹和index.html在一级,如:

<img src="img/commander.jpg">

Q: 如何在ionic中嵌入网页代码?
A: 使用ng-bind-html这个类,不过它会过滤原始html的标签,我们可以引入scesce.trustAsHtml()方法信任我们获取的网页

Q: 如何将template加载到某个tab或某个sidemenu项目下?
A:<ion-nav-view name="menuContent">可以指定name,然后在子状态中使用该name,ionic就知道该把该状态的template渲染到哪边了。例如:

 // signup page
 .state('auth.signup', {
   url: '/signup',
   views: {
       'auth-signup': {
           templateUrl: 'templates/auth-signup.html',
           controller: 'SignUpCtrl'
       }
   }
 })

另有一个tabs中声明该auth-signup:

 <ion-tab title="Sign Up" icon-on="ion-ios-personadd"
   icon-off="ion-ios-personadd-outline" href="#/auth/signup">
   <ion-nav-view name="auth-signup"></ion-nav-view>
</ion-tab>

Q: 运行serve命令时ionic报错?
A:

ionic $ An uncaught exception occured and has been reported to Ionic

看看你是不还有一个终端在运行着serve呢?

Q: 用docker跑ionic的时候,不能把地址绑定到0.0.0.0怎么处理?
A:可以用ionic serve -all的方法解决

Q: 加载页面的时候会看到双括号一闪而过?
A: angularjs在使用双括号的时候,第一个加载的页面,也就是应用中的index.html,其未被渲染好的模版可能会被用户看到。用ng-bind就不会遇到这个问题。造成这种现象的原因是,浏览器需要首先加载HTML页面,渲染它,然后Angular才有机会把它解释成你期望看到的内容。不过好消息是,在大多数的模版中你依然可以使用双括号.但是对于index.html页面中的数据绑定操作,建议使用ng-bind
ng-bind使用方式如下: <p ng-bind="greeting"></p>

Q: 更新了数据,如何让界面更新呢?
A: 可以用广播,注意broadcastemit的区别

Q: 如何实现IonicView中card上面有一列分割线的效果?
A: 在css里定义

#info-up {
  border-top: 4px solid #f06336;
}

Q: controller.js和service.js文件越来越大怎么办?
A:所有的控制器不必都放在controllers.js这一个文件中,可以新建controllers文件夹,
然后把每个controller都建一个.js文件,同理services和utils等都是.但注意要在index.html中head部分声明.但是为了避免他们相互覆盖,第一个加载的js中模块中要加[…],其他都不需要。如:

// File : /js/directives/mainDirective.js
angular.module('app.directives',[]);

// File : /js/directives/myGreatDirective.js
angular.module('app.directives')  
    .directive('myGreatDirective', function(){
        return {
            //...
        }
    });

// File : /js/directives/myBetterDirective.js
angular.module('app.directives')  
    .directive('myBetterDirective', function(){
        return {
            //...
        }
    });

...

angularjs-code-organization了解更多,嗯这篇文章写的还不是best practice,因为你还得记着自己把[]写到那个模块里了,统一地写在app.js中即可,在app.js最下面加上类似:

angular.module('fcws.controllers',['ionic', 'fcws.services']);
angular.module('fcws.services', []);

可以达到和上面一样的效果,而且可以统一管理.

Q: 如何寻找优秀的范例代码?
A:目前有些ionic 的app没有进行代码混淆,至少ionic官方的ionic view没有进行代码混淆,下载他们的app,文件名改成zip,解压,所有的 www文件都在assets文件夹中,相当于开源了有木有,看看那些最优秀的practice。看中哪些优秀的app,下下来,如何在googleplay上下载?把googleplay应用的地址贴到apps.evozi中。

Q: 如何显示相对时间?
A:如几分钟前,几天前等,可以用momentjs,看这篇教程

Q:发布应用的时候如果遇到翻译错误即MissingTranslation怎么办?
A:暂时的解决方法是,不进行翻译校正, 在 /platforms/android/build.gradle 中的android {}节中加入:

lintOptions {
    disable 'MissingTranslation'
    disable 'ExtraTranslation'
}

Q: 如何在列表右下方添加时间等信息?
A:span可以用来将时间之类的附加信息显示到列表右边,如下面会将创建时间显示在name的右边:

<ion-item class="item item-avatar-left " ng-repeat="message in messages">
    <img src="../../img/commander.jpg">
    <span class="item-note">{{message.create_at}}</span>
    <h2 >{{message.name}}</h2>
    <p >  {{message.content}}</p>
</ion-item >

Q:如何回到上一页面?
A:用$ionicHistory这个模块,引入该模块后使用goBack([backCount]),backCount指定回去多少个页面(-1代表回去一个页面),默认为-1

Q:如何关闭应用?
A:

ionic.Platform.exitApp();

Q: 在安卓设备上如何让title居中?
A: 在headerbar中添加align-title=”center”,如:

<ion-header-bar class="bar-positive" align-title="center">
     <h1 class="title">{{username}}</h1>
</ion-header-bar>

不过这个设置对ion-view无效,亲测,如果要统一让所有navbar上的title居中(包括上面的headerbar),可以在config里设置,如:

.config(function($stateProvider, $urlRouterProvider,$ionicConfigProvider) {
  $ionicConfigProvider.navBar.alignTitle('center');
  ...

如果要让某一个view title居中,可以用ionicNavBarDelegate[ionic](http://ionicframework.com/docs/api/service/ionicNavBarDelegate/)

Q: 如何让在sidemenu中的headerbar能够显示头像等其他信息?
A: 解决方案是去掉headerbar,添加一个avatar到sidemenu content中,如:

<ion-side-menu side="left">
    <ion-content class="bar-positive">
        <ion-list>
            <ion-item class="item item-avatar item-positive" href="#">
                <img src="img/commander.jpg">
                <h2 class=" light">
                    <i class="icon ion-ios-star"></i>{{title}}
                </h2>
                <a>{{username}}</a>
            </ion-item>

Q: ionic的subheader挡住了内容区域怎么办?
A: 解决方案是给加类has-subheader,同理也可以加has-header。如下:

<ion-content class="has-header has-subheader">

Q:对于需要添加数据的list,在添加数据后页面不能及时刷新造成卡顿怎么办?
A:可以使用$ionicScrollDelegate.resize();在添加数据后手动进行重新刷新,记得添加依赖

Q:ionic如何处理回退按钮?例如询问用户是否真的要退出应用
A:可以在app.js的.run方法中增加对硬件回退按钮的注册处理,这里我在大部分页面都想注册该事件,除去有二级历史页面的我单独判断了下,注意增加依赖。

$ionicPlatform.registerBackButtonAction(function(e) {
    var current_state_name = $state.current.name;
    if(current_state_name !== 'sidemenu.post'
     && current_state_name !== 'sidemenu.contact_town' &&
    current_state_name !== 'sidemenu.contact_people'){
        $ionicPopup.confirm({
            title: '退出应用',
            template: '您确定要退出xxxx吗?'
        }).then(function (res) {
            if (res) {
                //ionic.Platform.exitApp();
                navigator.app.exitApp();
            } else {
                console.log('You are not sure');
            }
        });
        e.preventDefault();
        return false;
    }else{
        navigator.app.backHistory();
    }
},100);

Q:ionic如何实现对每个请求都添加认证信息或认证失败自动重新登录?
A:在应用的注册或者登录部分,不记名token响应了这个请求并且这个token被存储到本地存储中。当你向后端请求一个服务时,你需要把这个token放在头部中。你可以在app.js的.config方法中使用AngularJS的拦截器实现这个。每次请求都会被拦截并且会把认证头部和值放到头部中,同理如果服务器端响应401或403,跳转到重新登录页面.

$httpProvider.interceptors.push(function ($q, $location, User, $rootScope) {
    return {
        'request': function (config) {
            config.headers = config.headers || {};
            if (User.getToken()) {
                config.headers.Authorization = 'Bearer ' + User.getToken();
            }
            return config;
        },
        'responseError': function (response) {
            if (response.status === 401 || response.status === 403) {
                //如果之前登陆过
                if (User.getToken()) {
                    $rootScope.$broadcast('unAuthenticed');
                }
            }
            return $q.reject(response);
        }
    };
});

Q:ionic如何实现搜索框内的全部清除按钮?
A:在label中的input不能嵌入按钮,因为ionic对于label中的tap事件会进行重定向到input上。解决方案是将label替换成span或div。如下面的搜索框,注意ng-model需要是一个对象才能置空,变量不行:

<span class="item-input-wrapper">
    <i class="icon ion-ios-search placeholder-icon"></i>
    <input type="search" placeholder="请输入姓名前缀" ng-model="search.key">
    <i class="icon ion-close-circled placeholder-icon" style="vertical-align: middle;"
        on-tap="clearSearch()" ng-if="search.key.length"></i>
</span>
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:763170次
    • 积分:8484
    • 等级:
    • 排名:第2280名
    • 原创:116篇
    • 转载:210篇
    • 译文:3篇
    • 评论:108条
    个人简介
    本人家乡是宁德,现在福州工作. 如果您觉得这系列的文章对你有所帮助,

    欢迎打赏。

    支付宝打赏


    微信打赏
    文章分类
    最新评论