源码下载:https://download.csdn.net/download/zhongcongxu01/89826872

在鸿蒙系统(HarmonyOS)的应用开发过程中,动态环境配置切换是一项重要的功能。它允许开发者根据不同的运行环境(如开发、测试、生产等)来调整应用的行为。本文将详细介绍如何利用鸿蒙系统的首选项机制来实现环境配置的动态切换,并通过一个具体的示例来展示这一过程。

【添加依赖】

harmony-utils:用于获取设备唯一ID(应用卸载重装不改变)

class-transformer:用于首选项本地数据取出json字符串转class使用(如果不使用框架,class的默认值就不生效了)

oh-package.json5

{
  "modelVersion": "5.0.0",
  "description": "Please describe the basic information.",
  "devDependencies": {
    "@ohos/hypium": "1.0.18",
    "@ohos/hamock": "1.0.0"
  },
  "dependencies": {
    "@pura/harmony-utils": "^1.0.3",
    "class-transformer": "^0.5.1"
  },
  "dynamicDependencies": {}
}

【添加页面】src/main/resources/base/profile/main_pages.json

{
  "src": [
    "pages/Index",
    "pages/TestSetting"
  ]
}

【首选项工具类】src/main/ets/common/MyPreferencesUtil.ets

import dataPreferences from '@ohos.data.preferences';
import bundleManager from '@ohos.bundle.bundleManager';
import { common } from '@kit.AbilityKit';
import { DeviceUtil } from '@pura/harmony-utils';
import { plainToClassFromExist } from 'class-transformer'

export class MyPreferencesUtil {
  //日志过滤器
  private static readonly LOG: string = "====MyPreferencesUtil"
  //本地保存的文件名,和文件内的key名这里打算共用一个就行
  private static readonly FILENAME_AND_KEY: string = 'FILENAME_AND_KEY'

  //=========单例模式,保存数据到内存实例 end=========
  static formatTimestamp(timestamp: number): string {
    const date = new Date(timestamp);
    const year = date.getFullYear();
    const month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份从 0 开始,所以加 1
    const day = ('0' + date.getDate()).slice(-2);
    const hours = ('0' + date.getHours()).slice(-2);
    const minutes = ('0' + date.getMinutes()).slice(-2);
    const seconds = ('0' + date.getSeconds()).slice(-2);

    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  }

  /**
   * 从磁盘本地读取数据到内存,赋值给instance
   * @param context 在pages中使用getContext(this),在EntryAbility中,使用this.context
   */
  public static async getData(context: Context) {
    try {
      console.info(MyPreferencesUtil.LOG, 'getData');
      let options: dataPreferences.Options = { name: MyPreferencesUtil.FILENAME_AND_KEY };
      let file = await dataPreferences.getPreferences(context, options)
      console.info(MyPreferencesUtil.LOG, 'getData', 'file succ');
      let value = file.getSync(MyPreferencesUtil.FILENAME_AND_KEY, JSON.stringify(MySetting.getInstance()))
      console.info(MyPreferencesUtil.LOG, 'getData', 'get succ', 'value:' + value);
      MySetting.updateInstance(value.toString())
      console.info(MyPreferencesUtil.LOG, 'getData', 'assign succ');
      let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT;
      let data = bundleManager.getBundleInfoForSelfSync(bundleFlags); //开始保存app的版本名称和版本号
      MySetting.getInstance().mEnvirInfo.versionName = data.versionName
      MySetting.getInstance().mEnvirInfo.versionCode = data.versionCode
      MySetting.getInstance().mEnvirInfo.deviceId = DeviceUtil.getDeviceId()
      MySetting.getInstance().mEnvirInfo.installTime = MyPreferencesUtil.formatTimestamp(data.installTime)
      MySetting.getInstance().mEnvirInfo.updateTime = MyPreferencesUtil.formatTimestamp(data.updateTime)
      console.info(MyPreferencesUtil.LOG, 'getData', 'set versionName and versionCode succ');
    } catch (e) {
      console.error(MyPreferencesUtil.LOG, 'getData', JSON.stringify(e));
    }
  }

  /**
   * 数据备份至磁盘本地
   *
   * @param context getContext(this)
   */
  public static async saveData(context: common.UIAbilityContext) {
    try {
      console.info(MyPreferencesUtil.LOG, 'saveData');
      let file = await dataPreferences.getPreferences(context, MyPreferencesUtil.FILENAME_AND_KEY)
      console.info(MyPreferencesUtil.LOG, 'saveData', 'file succ');
      await file.put(MyPreferencesUtil.FILENAME_AND_KEY, JSON.stringify(MySetting.getInstance()))
      console.info(MyPreferencesUtil.LOG, 'saveData', 'put succ');
      await file.flush()
      console.info(MyPreferencesUtil.LOG, 'saveData', 'flush succ');
    } catch (e) {
      console.error(MyPreferencesUtil.LOG, 'saveData', JSON.stringify(e));
    }
  }
}

//本地保存的配置信息模板
export class MySetting {
  //不希望被别人用new MySetting()造成误操作,所以这里用单例
  //=========单例模式,保存数据到内存实例 start=========
  private static instance: MySetting;

  private constructor() {
  }

  /**
   * 通过单例,获取本地映射到内存中的实例
   * @returns 内存中本地数据的实例
   */
  public static getInstance() {
    if (!MySetting.instance) {
      MySetting.instance = new MySetting();
    }
    return MySetting.instance;
  }

  //从本地信息修改的时候,需要修改当前配置信息
  public static updateInstance(value: string) {
    // MySetting.instance = JSON.parse(value)
    MySetting.instance = plainToClassFromExist(new MySetting(), JSON.parse(value))
  }

  /** 本地要保存的用户信息 */
  public mUserInfo: UserInfo = new UserInfo()
  // 本地要保存的环境信息
  public mEnvirInfo: EnvirInfo = new EnvirInfo()
}

/**
 * 用户信息
 */
export class UserInfo {
  /**
   * 用户登录成功后要保存的token
   */
  public token: string = ""
  memberId: string = ""
  unionId: string = ""
  unionCode: string = ""
}

/**
 * 环境信息
 */
export class EnvirInfo {
  /**
   * 首次启动的弹窗是否点击过“同意”。true:已同意,false:没同意
   */
  public isAgreement: boolean = false
  //首次启动是否查看过引导页,true:看过,false:没看过
  public isGuideScreen: boolean = false
  /** 蒙层引导页弹出次数(首页) */

  private launchGuideNum: number = 0;

  public getLaunchGuideNum() {
    return this.launchGuideNum;
  }

  public addLaunchGuideNum() {
    this.launchGuideNum += 1;
  }

  /** 蒙层引导页弹出次数(我的页面)  */
  private launchGuideMyNum: number = 0;

  public addLaunchGuideMyNum() {
    this.launchGuideMyNum += 1;
  }

  public getLaunchGuideMyNum() {
    return this.launchGuideMyNum;
  }

  /**
   * 当前app的版本名称
   */
  public versionName: string = ''
  /**
   * 当前app的版本号
   */
  public versionCode: number = 0
  /**appid*/
  public deviceId: string = ""
  //缓存信息
  public cacheSize: number = 0
  public installTime: string = ""
  public updateTime: string = ""
  public defaultEnv: EnvInfoKey = EnvInfoKey.GCC //默认环境
}

export enum EnvInfoKey {
  GCC = "GCC",
  ORD = "ORD",
  CAS = "CAS",
  PUB = "PUB",
  MBC = "MBC",
  TPL = "TPL"
}

export class EnvInfo {
  static env: Record<EnvInfoKey, EnvInfo> = {
    [EnvInfoKey.GCC]: new EnvInfo(EnvInfoKey.GCC, "通用环境", 'http://web.GCC.com', 'https://api.GCC.com'),
    [EnvInfoKey.ORD]: new EnvInfo(EnvInfoKey.ORD, "普通环境", "https://ORD", "https://apit.ORD"),
    [EnvInfoKey.CAS]: new EnvInfo(EnvInfoKey.CAS, "云服务环境", "https://CAS", "https://api.CAS"),
    [EnvInfoKey.PUB]: new EnvInfo(EnvInfoKey.PUB, "公共环境", "https://mPUB", "https://api.PUB"),
    [EnvInfoKey.MBC]: new EnvInfo(EnvInfoKey.MBC, "多包配置", "https://mMBC", "https://api.MBC"),
    [EnvInfoKey.TPL]: new EnvInfo(EnvInfoKey.TPL, "模板环境", "https://TP", "https://api.TPL")
  }
  typeValue: EnvInfoKey
  typeName: string = '普通环境'
  webHost: string = 'https://xxx' //网页域名(业务域名)
  apiHost: string = 'https://xxx' //接口域名

  constructor(typeValue: EnvInfoKey, typeName: string, webHost: string, apiHost: string) {
    this.typeValue = typeValue
    this.typeName = typeName
    this.webHost = webHost
    this.apiHost = apiHost
  }
}

【程序入口获取本地首选项信息】src/main/ets/entryability/EntryAbility.ets

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { MyPreferencesUtil } from '../common/MyPreferencesUtil';

export default class EntryAbility extends UIAbility {
  onCreate(): void {
    MyPreferencesUtil.getData(this.context)
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/Index');
  }
}

【配置页】src/main/ets/pages/TestSetting.ets

//测试设置页面
import { EnvInfo, MyPreferencesUtil, MySetting, UserInfo } from '../common/MyPreferencesUtil';
import { common } from '@kit.AbilityKit';
import deviceInfo from '@ohos.deviceInfo';

class ItemBean {
  name: string = ""
  value: string = ""
}

@Entry
@Component
struct TestSetting {
  private select: number = 0
  private fruits: string[] = []
  @State textValue: string = ''
  @State dataArr: Array<ItemBean> = []
  @State defaultEnvInfo: EnvInfo | undefined = undefined

  onCancel() {
    console.info('Callback when the first button is clicked')
  }

  onAccept() {
    console.info('Callback when the second button is clicked')
  }

  exitApp() {
    console.info('Click the callback in the blank area')
  }

  aboutToAppear(): void {
    this.defaultEnvInfo = EnvInfo.env[MySetting.getInstance().mEnvirInfo.defaultEnv]
    //读取本地配置信息渲染到列表
    this.fruits.length = 0
    let i = 0
    for (let key of Object.keys(EnvInfo.env)) {
      this.fruits.push(EnvInfo.env[key].typeName)
      if (MySetting.getInstance().mEnvirInfo.defaultEnv == key) {
        this.select = i
      }
      i++
    }

    this.dataArr = [{
      'name': 'versionName',
      'value': MySetting.getInstance().mEnvirInfo.versionName
    }, {
      'name': 'versionCode',
      'value': MySetting.getInstance().mEnvirInfo.versionCode.toString()
    }, {
      'name': 'installTime',
      'value': MySetting.getInstance().mEnvirInfo.installTime
    }, {
      'name': 'updateTime',
      'value': MySetting.getInstance().mEnvirInfo.updateTime
    }, {
      'name': 'deviceId',
      'value': MySetting.getInstance().mEnvirInfo.deviceId
    }, {
      'name': '设备市场名称',
      'value': deviceInfo.marketName
    }, {
      'name': '当前环境类型',
      'value': this.defaultEnvInfo.typeName
    }, {
      'name': 'web业务域名',
      'value': this.defaultEnvInfo.webHost
    }, {
      'name': 'api接口域名',
      'value': this.defaultEnvInfo.apiHost
    }
    ]
  }

  build() {
    Scroll() {
      Column() {
        Text().height('34lpx')
        Text('基本信息')
          .fontSize('48lpx')
          .fontWeight(FontWeight.Normal)
        Text().height('72lpx')
        ForEach(this.dataArr, (item: ItemBean) => {
          Stack() {
            Text()
              .width('718lpx').height('144lpx')
              .borderRadius('40lpx')
              .backgroundColor('#eeeeee')
            Column() {
              Text(item.name)
                .fontSize('30lpx')
                .fontColor('#232A35')
                .margin({ left: '50lpx' })
              Text(item.value)
                .fontSize('26lpx')
                .fontColor('#718193')
                .margin({ top: '20lpx', left: '50lpx' })
            }.width('100%')
            .alignItems(HorizontalAlign.Start)
            .onClick(() => {
              if (item.name == '当前环境类型') {
                TextPickerDialog.show({
                  range: this.fruits,
                  selected: this.select,
                  disappearTextStyle: { color: Color.Red, font: { size: 15, weight: FontWeight.Lighter } },
                  textStyle: { color: Color.Black, font: { size: 20, weight: FontWeight.Normal } },
                  selectedTextStyle: { color: Color.Blue, font: { size: 30, weight: FontWeight.Bolder } },
                  onAccept: (value: TextPickerResult) => {
                    // 设置select为按下确定按钮时候的选中项index,这样当弹窗再次弹出时显示选中的是上一次确定的选项
                    this.select = value.index as number;

                    console.info(`this.select:${this.select}`)
                    //清空内存中用户信息
                    MySetting.getInstance().mUserInfo = new UserInfo()
                    //修改内存中环境信息
                    this.fruits
                    for (let key of Object.keys(EnvInfo.env)) {
                      if (this.fruits[this.select] == EnvInfo.env[key].typeName) {
                        MySetting.getInstance().mEnvirInfo.defaultEnv = EnvInfo.env[key].typeValue
                        break;
                      }
                    }
                    //保存内存中的信息 将内存中的所有信息写入到磁盘首选项
                    MyPreferencesUtil.saveData(getContext() as common.UIAbilityContext)
                    //退出app
                    let context = getContext(this) as common.UIAbilityContext
                    context.terminateSelf()
                  },
                  onCancel: () => {
                    console.info("TextPickerDialog:onCancel()")
                  },
                  onChange: (value: TextPickerResult) => {
                    console.info("TextPickerDialog:onChange()" + JSON.stringify(value))
                  }
                })
              }
            })
          }.margin({ bottom: '16lpx' })
        })
      }.width('100%')
    }.scrollBar(BarState.Off)
  }
}

【主页】src/main/ets/pages/Index.ets

import { router } from '@kit.ArkUI';
import { EnvInfo, MySetting } from '../common/MyPreferencesUtil';
import { bundleManager } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  aboutToAppear(): void {
    let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT;
    let data = bundleManager.getBundleInfoForSelfSync(bundleFlags); //开始保存app的版本名称和版本号
    console.info(`data:${JSON.stringify(data)}`)
  }
  build() {
    Column() {
      Text(`当前环境信息:${JSON.stringify(EnvInfo.env[MySetting.getInstance().mEnvirInfo.defaultEnv])}`)
      Button('本地信息、环境配置页').onClick(() => {
        router.pushUrl({ url: 'pages/TestSetting' })
      })
    }
    .height('100%')
    .width('100%')
  }
}

zhongcx
1 声望3 粉丝