ionic 运行过程中动态切换API服务器地址
发布于 1年前 作者 ifengkou 799 次浏览 来自 分享

场景、需求

场景

APP以项目的形式提供,一个客户需要部署一套服务器,一个APP,所以APP的后台服务器地址不能写死。而且要求如果有wifi且在内网,需要用内网服务器地址,如果用3G或者4G,则需切换为外网服务器地址

需求

APP第一次运行,如果没有设置过服务器地址,需要设置好后台服务器地址(含内网和外网,外网是必选,内网是可选)

APP运行过程中,如果用户手机网络制式发生改变,则需要根据移动网络制式选择合适的服务器地址

原有URL的设置

以前APP的API地址,是直接写到一个constant里面,例如:

(function () {
  "use strict";
  angular.module("gaia.config", [])
    .constant("ENV", {
      "version": "1.0.1",
      "name": "production",
      "debug": true,
      "api": "http://111.111.111.111:8088/gaia/api",
    });
})();

resource的调用

var resource = $resource(ENV.api + '/customer',{},{
      login:{
        method:'post',
        url:ENV.api + '/customer/login'
      },
      accesstoken:{
        method:'get',
        url:ENV.api + '/customer/accesstoken'
      }
    });

方案一

(后面实现方案有部分变动)

保留ENV,APP第一次启动将设置的url存到localstorage里面,在以后每次启动前,从localstorage里面取出来赋值给ENV.api,当网络制式发生改变时,再根据情况赋值改变ENV.api。所有与后台相关的Service 的$resource 的初始化都依赖于ENV.api。

设计的关键点:

  • 启动时需要检查localstorage里面是否有url的值,没有则弹出设置页
  • ENV.api的赋值一定要先于APP的启动,否则Service的$resource的url 都为空了
  • Service 需要将$resource的定义封装并开放出接口,便于后期改变$resource的url定义
  • 网络制式改变,ENV.api的改变,Service的$resource的重新定义

设置页面 请忽略美观(-__-)b urlsetting.png

Service $resource 声明方式的改造:

var resource = null;
  var _initResource = function(apiUrl){
    resource = $resource(apiUrl + '/customer',{},{
      login:{
        method:'post',
        url:apiUrl + '/customer/login'
      },
      accesstoken:{
        method:'get',
        url:apiUrl + '/customer/accesstoken'
      }
    });
  };
  _initResource(ENV.api);
return {
    initResource:function(url){
      _initResource(url);
    },
.....

新增Service,统一变更$resource

每次变更就调用先设置ENV.api,再_Sys.changeResource(ENV.api);

(function () {
  'use strict';
  angular.module('gaia.services')
    .factory('_Sys', function (ENV, User, Projects, Plans) {
      return {
        changeResource: function (url) {
          User.initResource(url);
          Projects.initResource(url);
          Plans.initResource(url);
        }
      };
    });
})();

网络制式切换,调整URL

关于网络制式的监控的相关细节见:ngcordova 监控网络制式改变

$rootScope.$on('$cordovaNetwork:online', function (event, networkState) {
    var type = $cordovaNetwork.getNetwork();
    if (type == Connection.WIFI) {
      var wifiApi = Settings.getWIFIAPI();
      if (wifiApi) {
        //test方法定义见方案二Setting定义
        Settings.test(wifiApi).$promise.then(function (response) {
          if (response.success) {
            //切换内网服务器地址中....
            _Sys.changeResource(wifiApi);
          }
        }, function (e) {});
      }
    }
    else if (type == Connection.CELL_4G || type == Connection.CELL_3G) {
      var wlanApi = Settings.getAPI();
      //切换移动网(3G|4G)服务器地址中....
      _Sys.changeResource(wlanApi);
    }
  });

方案二

大体思路同方案一,只是在思想方案一过程中,又是localstorage 又是ENV.api,各种判断,给绕晕了,后来一想,url最终还是以localstorage为准,何不抛弃ENV.api,实现大统一(●ˇ∀ˇ●)

设计思路改动点:

  • 抛弃ENV.api,所有获取和设置,均以localstorage为准
  • 简化、优化API地址的获取和设置,见下面Setting Service 的定义(新增getAPI(),getWIFIAPI())
  • 所有Service $resource中的URL,均取于Setting.getAPI()方法
  • 进入第一个页面前,判断Setting.getAPI()的值是否存在,不存在则弹出设置页面进行设置

1.用户设置的API地址,存储到localstorage里面,定义两个基础Service,一个用于localstorage操作,一个用于APP参数设置

//Storage Service 定义

(function(){
  'use strict';
  angular.module('gaia.services')
    .factory('Storage',function($log){
      $log.debug("Storage Service init");
      return {
        set:function(key,data){
          return window.localStorage.setItem(key,window.JSON.stringify(data));
        },
        get:function(key){
          return window.JSON.parse(window.localStorage.getItem(key));
        },
        remove:function(key){
          return window.localStorage.removeItem(key);
        }
      };
    });
})();

//Settings Service 定义

(function () {
  'use strict';
  angular.module('gaia.services')
    .factory('Settings', function ($resource, $log, Storage) {
      var storageKey = 'settings';
      var _settings = Storage.get(storageKey) || {};
      var addOn = '/gaia/api';
      return {
        getSettings: function () {
          return _settings;
        },
        save: function (settings) {
          Storage.set(storageKey, settings);
          _settings = settings;//改变内存中的_settings,便于每次调用getAPI时都能取到最新值
          return settings;
        },
        getAPI: function () {
          if (_settings.wlan) {
            return "http://" + _settings.wlan + addOn;
          }
          return "";
        },
        getWIFIAPI: function () {
          if (_settings.wifiMode && _settings.wifi) {
            return "http://" + _settings.wifi + addOn;
          }
          return "";
        },
        test: function (url) {
          var resource = $resource("http://" + url + addOn + "/test", {}, {
            query: {
              method: 'get',
              isArray: false,
              timeout: 2000
            }
          });
          return resource.query();
        }
      };
    });
})();

2.Service $resource 的部分改动

var resource = null;
  var _initResource = function(apiUrl){
    resource = $resource(apiUrl + '/customer',{},{
      login:{
        method:'post',
        url:apiUrl + '/customer/login'
      },
      accesstoken:{
        method:'get',
        url:apiUrl + '/customer/accesstoken'
      }
    });
  };
 //将此处的ENV.api 换成Settings.getAPI()
 // _initResource(ENV.api);
  _initResource(Settings.getAPI());

3.检测是否存在API地址,不存在则弹出设置页面

$scope.api = Settings.getAPI();
$ionicModal.fromTemplateUrl('templates/urlSetting.html', {
    scope: $scope
  }).then(function (modal) {
    $scope.settingModal = modal;
    if ((!$scope.api) || ($scope.api.indexOf("http://") === -1)) {
      if (window.StatusBar) {
        StatusBar.styleDefault();
      }
      $scope.settingModal.show();
    }
  });

//保存设置值方法
$scope.saveSettings = function () {
    //1.save setting 到localstorage
    if (!$scope.settings.wifiMode) {
      $scope.settings.wifi = "";
    }
    Settings.save($scope.settings);
    $ionicLoading.show({
      noBackdrop: true,
      template: "<div><h1><i class='icon ion-checkmark-circled balanced'></i></h1>保存成功</div>",
      duration: 1000
    });
    $scope.api = Settings.getAPI();
    //2.变更所有Service 中的resource
    _Sys.changeResource($scope.api);
    $scope.settingModal.hide();
  };

总结

为了实现APP的后台API地址动态改变,只要找到问题的核心,不外乎围绕着API_URL 的获取 和设置 来实现该功能

获取:

  • 判断localstroage是否存储了API_URL - 增加判断方法
  • 与后台服务器请求相关的Service - 变更$resource 的定义方法,并开放出改变的接口

设置:

  • localstroage里面没有API_URL ,弹出页,保存时
  • 网络制式发生变化时

keywords:

ionic,网络制式,动态切换,变更,API,服务器地址,$resource,localstorage

原文见:http://www.cnblogs.com/sloong/p/5151019.html

回到顶部