Skip to content

Latest commit

 

History

History
657 lines (526 loc) · 14.4 KB

File metadata and controls

657 lines (526 loc) · 14.4 KB

QuickBox 最佳实践指南

本文档基于实际项目经验,提供 QuickBox 框架的最佳实践和使用建议。

📱 加桌(添加到桌面)功能

基本使用

import QuickBox from 'quickbox';

// 检查是否已添加到桌面
const isInstalled = await QuickBox.ShortcutUtils.checkInstalled();
if (!isInstalled) {
  // 引导用户添加桌面
}

// 获取加桌方式
const method = QuickBox.ShortcutUtils.getInstallMethod();
if (method === 'install') {
  // 华为/OPPO:使用 API 方式
  await QuickBox.ShortcutUtils.install({
    success: () => {
      console.log('添加成功');
    },
    fail: (err) => {
      console.log('添加失败', err);
    }
  });
} else {
  // 其他厂商:使用组件方式
  // 在模板中使用 <shortcut-button> 组件
}

在页面中使用

华为/OPPO(使用 API):

// script
async onAddDesktop() {
  const method = QuickBox.ShortcutUtils.getInstallMethod();
  if (method === 'install') {
    try {
      await QuickBox.ShortcutUtils.install({
        success: () => {
          prompt.showToast({ message: '添加成功' });
        },
        fail: (err) => {
          prompt.showToast({ message: '添加失败,请重试' });
        }
      });
    } catch (error) {
      console.error('添加桌面失败', error);
    }
  }
}

其他厂商(使用组件):

<!-- template -->
<shortcut-button 
  value="添加至桌面" 
  add-type="8"
  onclick="onAddDesktop"
></shortcut-button>

加桌拦截场景

在章节阅读页等关键页面,可以拦截返回操作,引导用户添加桌面:

onBackPress() {
  const isInstalled = await QuickBox.ShortcutUtils.checkInstalled();
  if (!isInstalled) {
    // 显示加桌引导弹窗
    this.showAddDesktopDialog = true;
    return true; // 阻止返回
  }
  return false; // 允许返回
}

💰 支付配置管理

使用配置管理工具

import QuickBox from 'quickbox';

// 方式1:单独获取各厂商配置
const huaweiConfig = await QuickBox.ConfigManager.getHuaweiConfig(
  'https://api.example.com/app/config/getHuaweiConfig'
);

await QuickBox.huaweiPay({
  applicationID: huaweiConfig.applicationID,
  publicKey: huaweiConfig.publicKey,
  productId: 'product_123',
  amount: 1000,
  orderInfo: 'ORDER_123'
});

// 方式2:自动根据当前厂商获取配置
const config = await QuickBox.ConfigManager.getConfigByVendor({
  huawei: 'https://api.example.com/app/config/getHuaweiConfig',
  xiaomi: 'https://api.example.com/app/config/getXiaomiConfig',
  oppo: 'https://api.example.com/app/config/getOppoConfig',
  vivo: 'https://api.example.com/app/config/getVivoConfig'
});

配置缓存

建议在应用启动时获取并缓存配置:

// app.ux
let paymentConfigs = {};

async onCreate() {
  // 预加载支付配置
  try {
    const vendor = QuickBox.getVendorInfo().vendor;
    if (vendor === 'huawei' || vendor === 'honor') {
      paymentConfigs.huawei = await QuickBox.ConfigManager.getHuaweiConfig(
        'https://api.example.com/app/config/getHuaweiConfig'
      );
    }
    // ... 其他厂商
  } catch (error) {
    console.error('加载支付配置失败', error);
  }
}

🌐 网络请求增强

配置统一参数

import QuickBox from 'quickbox';

// 配置统一参数(会自动添加到所有请求)
QuickBox.Request.configure({
  baseURL: 'https://api.example.com',
  baseParams: {
    max_app_id: 'YOUR_APP_ID',
    max_version: '1.0.0',
    max_package: 'com.example.app',
    max_brand: QuickBox.getVendorInfo().vendor,
    max_platform: 1,
    max_os: 1
  },
  timeout: 20000,
  headers: {
    'Content-Type': 'application/json'
  }
});

添加请求拦截器

// 添加Token到请求头
QuickBox.Request.addRequestInterceptor((options) => {
  const token = getToken(); // 从存储中获取token
  return {
    ...options,
    header: {
      ...options.header,
      Authorization: token
    }
  };
});

添加响应拦截器

// 统一处理响应数据
QuickBox.Request.addResponseInterceptor((response) => {
  // 假设后端返回格式为 { code: 0, data: {...}, msg: 'success' }
  if (response.code === 0) {
    return response.data;
  } else {
    throw new Error(response.msg || '请求失败');
  }
});

401自动登录

QuickBox.Request.configure({
  onUnauthorized: async () => {
    // 清除token
    await QuickBox.removeStorage('token');
    // 跳转到登录页
    QuickBox.navigateTo({ uri: '/pages/login' });
  }
});

错误处理

try {
  const data = await QuickBox.Request.get('/api/users');
} catch (error) {
  // 错误已经被拦截器处理,这里可以做额外处理
  console.error('请求失败', error);
}

📱 原生广告完整示例

小米特殊处理

小米需要使用 <ad-clickable-area> 包裹点击区域:

<!-- template -->
<ad 
  id="ad" 
  adid="{{nativeAdData.adId}}" 
  type="native" 
  class="ad"
  onadclick="onAdClick"
  onadclose="onAdClose"
>
  <ad-clickable-area if="{{isMi}}" style="width: 100%;height: 100%">
    <div class="adbtn" onclick="onAdClick">
      <text>查看详情</text>
    </div>
  </ad-clickable-area>
</ad>
// script
import QuickBox from 'quickbox';

async initNativeAd() {
  const isMi = QuickBox.isXiaomi();
  
  // 创建原生广告
  const nativeAd = QuickBox.createNativeAd({
    adUnitId: 'YOUR_AD_UNIT_ID',
    adCount: 1 // 小米/OPPO/vivo必传
  });

  if (!nativeAd) {
    console.log('不支持原生广告');
    return;
  }

  // 监听加载事件
  nativeAd.onLoad((data) => {
    const adList = data.adList || [];
    if (adList.length > 0) {
      const adData = adList[0];
      this.nativeAdData = {
        adId: adData.adId,
        title: adData.title,
        desc: adData.desc,
        imgUrlList: adData.imgUrlList,
        videoUrlList: adData.videoUrlList
      };
      
      // 上报曝光
      nativeAd.reportAdShow({ adId: adData.adId });
    }
  });

  nativeAd.onError((err) => {
    console.error('原生广告加载失败', err);
  });
}

onAdClick() {
  if (this.nativeAd) {
    this.nativeAd.reportAdClick({ adId: this.nativeAdData.adId });
  }
}

华为/荣耀特殊处理

华为/荣耀需要预加载,并且需要显示关闭按钮:

const nativeAd = QuickBox.createNativeAd({
  adUnitId: 'YOUR_AD_UNIT_ID',
  allowRecommend: true // 荣耀必传
});

// 华为/荣耀会自动调用 load(),但可以手动监听
if (QuickBox.isHuawei() || QuickBox.isHonor()) {
  nativeAd.onLoad((data) => {
    // 处理加载成功
  });
}

OPPO/vivo特殊处理

OPPO/vivo使用 preloadAd,需要 adCount 参数:

const nativeAd = QuickBox.createNativeAd({
  adUnitId: 'YOUR_AD_UNIT_ID',
  adCount: 1 // OPPO必传
});

📖 阅读器工具使用

内容分页

import { ReaderUtils } from 'quickbox';

// 获取设备信息
const deviceInfo = await QuickBox.getSystemInfo();

// 分页内容
const result = ReaderUtils.splitContentIntoPages({
  deviceInfo: {
    windowWidth: deviceInfo.windowWidth,
    windowHeight: deviceInfo.windowHeight,
    screenDensity: deviceInfo.screenDensity
  },
  content: ['段落1内容', '段落2内容'],
  fontSize: 30,
  lineHeightRatio: 2.1,
  padding: 30,
  topPadding: 100
});

console.log('分页结果', result.pages);
console.log('每页行数', result.linesPerPage);
console.log('每行字符数', result.charsPerLine);

插入广告页

// 在分页内容中插入广告页
const pagesWithAd = ReaderUtils.insertAdPages(
  result.pages,
  'iaa广告页', // 广告页标记
  0, // 第一页索引
  5, // 每5页插入一个广告
  true // 第一页前也插入
);

Banner广告样式计算

const deviceInfo = await QuickBox.getSystemInfo();
const isHuaweiGroup = QuickBox.isHuaweiGroup();

const bannerStyle = ReaderUtils.calculateBannerStyle(deviceInfo, {
  height: 57,
  bottom: 20,
  isHuaweiGroup
});

// 创建Banner广告
const bannerAd = QuickBox.createBannerAd({
  adUnitId: 'YOUR_AD_UNIT_ID',
  autoWidth: true, // 自动适配宽度
  style: bannerStyle
});

🎯 厂商检测最佳实践

条件渲染

<!-- template -->
<block if="{{isHuawei || isOppo}}">
  <!-- 华为/OPPO特殊UI -->
</block>

<block else>
  <!-- 其他厂商UI -->
</block>
// script
computed: {
  isHuawei() {
    return QuickBox.isHuawei();
  },
  isOppo() {
    return QuickBox.isOppo();
  },
  isMi() {
    return QuickBox.isXiaomi();
  }
}

功能判断

// 根据厂商使用不同的API
if (QuickBox.isHuawei() || QuickBox.isHonor()) {
  // 华为/荣耀特殊处理
  await QuickBox.huaweiPay({...});
} else if (QuickBox.isXiaomi()) {
  // 小米特殊处理
  await QuickBox.xiaomiPay({...});
}

🔧 应用初始化最佳实践

// app.ux
import QuickBox from 'quickbox';

export default {
  async onCreate() {
    // 1. 配置网络请求
    QuickBox.Request.configure({
      baseURL: 'https://api.example.com',
      baseParams: () => ({
        max_app_id: this.getAppId(),
        max_version: this.getVersion(),
        max_brand: QuickBox.getVendorInfo().vendor
      }),
      onUnauthorized: async () => {
        await this.handleUnauthorized();
      }
    });

    // 2. 预加载支付配置
    await this.preloadPaymentConfigs();

    // 3. 检查加桌状态
    const isInstalled = await QuickBox.ShortcutUtils.checkInstalled();
    this.isDesktop = isInstalled;

    // 4. 初始化其他功能
    await this.initOtherFeatures();
  },

  async preloadPaymentConfigs() {
    const vendor = QuickBox.getVendorInfo().vendor;
    try {
      if (vendor === 'huawei' || vendor === 'honor') {
        this.paymentConfigs.huawei = await QuickBox.ConfigManager.getHuaweiConfig(
          'https://api.example.com/app/config/getHuaweiConfig'
        );
      }
      // ... 其他厂商
    } catch (error) {
      console.error('预加载支付配置失败', error);
    }
  }
}

🔑 Token管理

使用Token管理器

import QuickBox from 'quickbox';

// 获取华为Token(自动缓存)
const hwToken = await QuickBox.TokenManager.getHuaweiToken('YOUR_APPID', 'MEMBER_ID');

// 获取小米Token(自动缓存)
const miToken = await QuickBox.TokenManager.getXiaomiToken('MEMBER_ID');

// 根据厂商自动获取Token
const token = await QuickBox.TokenManager.getTokenByVendor({
  huaweiAppid: 'YOUR_APPID',
  xiaomiMemberId: 'MEMBER_ID'
});

// 清除Token缓存
await QuickBox.TokenManager.clearToken('hwToken_YOUR_APPID');

Token缓存机制

Token管理器会自动缓存Token到内存和本地存储,避免重复请求:

  • 内存缓存:快速访问,应用重启后失效
  • 本地存储:持久化缓存,应用重启后仍然有效
  • 过期管理:支持设置过期时间,自动清除过期Token

📊 应用状态管理

应用就绪检查

// app.ux
import QuickBox from 'quickbox';

export default {
  async onCreate() {
    // 初始化应用
    await this.initApp();
    
    // 设置应用就绪
    QuickBox.AppStateManager.setReady(true);
  }
}

// 其他页面
export default {
  async onInit() {
    // 等待应用就绪后再执行
    await QuickBox.AppStateManager.waitForReady();
    
    // 安全执行操作
    const data = await QuickBox.Request.get('/api/data');
  }
}

确保就绪后执行

// 方式1:使用 waitForReady
await QuickBox.AppStateManager.waitForReady();
const data = await QuickBox.Request.get('/api/data');

// 方式2:使用 ensureReady(推荐)
const data = await QuickBox.AppStateManager.ensureReady(async () => {
  return await QuickBox.Request.get('/api/data');
});

📍 来源追踪

设置来源信息

// 设置来源名称(7天后过期)
await QuickBox.SourceTracker.setSource('content_123', 'origin_name', '书城', 7);

// 设置渠道名称(7天后过期)
await QuickBox.SourceTracker.setSource('content_123', 'chl_name', '文末推荐', 7);

// 设置一级来源(90天后过期)
await QuickBox.SourceTracker.setSource('content_123', 'first_origin', '书城', 90);

获取来源信息

// 获取单个来源
const originName = await QuickBox.SourceTracker.getSource('content_123', 'origin_name');

// 获取所有来源
const sources = await QuickBox.SourceTracker.getAllSources('content_123');
// { origin_name: '书城', chl_name: '文末推荐', first_origin: '书城' }

// 检查来源是否有效(未过期)
const isValid = await QuickBox.SourceTracker.isSourceValid('content_123', 'origin_name');

清除来源

// 清除单个来源
await QuickBox.SourceTracker.clearSource('content_123', 'origin_name');

// 清除所有来源
await QuickBox.SourceTracker.clearSource('content_123');

🛠️ 通用工具函数

防抖和节流

// 防抖:连续调用只会在指定时间后执行一次
const debouncedSearch = QuickBox.debounce((keyword) => {
  console.log('搜索:', keyword);
}, 300);

// 节流:指定时间内最多执行一次
const throttledScroll = QuickBox.throttle(() => {
  console.log('滚动事件');
}, 100);

// 使用示例
input.onInput((e) => {
  debouncedSearch(e.value);
});

window.addEventListener('scroll', throttledScroll);

延迟和重试

// 延迟执行
await QuickBox.delay(1000); // 等待1秒

// 重试机制
const result = await QuickBox.retry(
  () => QuickBox.Request.get('/api/data'),
  3, // 最多重试3次
  1000 // 每次重试间隔1秒
);

其他工具函数

// 格式化文件大小
QuickBox.formatFileSize(1024); // "1 KB"
QuickBox.formatFileSize(1048576); // "1 MB"

// 深拷贝
const cloned = QuickBox.deepClone(originalObject);

📝 注意事项

  1. 原生广告

    • 小米必须使用 <ad-clickable-area> 包裹点击区域
    • 华为/荣耀需要预加载
    • OPPO需要 adCount 参数
  2. Banner广告

    • 华为宽度固定360,其他厂商750
    • 使用 autoWidth: true 自动适配
  3. 加桌功能

    • 华为/OPPO使用API方式
    • 其他厂商使用组件方式
  4. 支付配置

    • 建议在应用启动时预加载
    • 可以缓存配置避免重复请求
  5. 网络请求

    • 统一参数通过 baseParams 配置
    • 401错误会自动触发 onUnauthorized
    • 错误会自动显示Toast提示(可通过 showErrorToast: false 关闭)