ionic 運作過程中動态切換API伺服器位址
keywords:
ionic,phonegap,cordova,網絡制式,動态切換,變更,API,伺服器位址,$resource,localstorage,url
場景、需求
場景
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

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 ,彈出頁,儲存時
- 網絡制式發生變化時
【原創】,轉載請帶上原位址http://www.cnblogs.com/sloong/p/5151019.html