δΈ­

App Configuration

This comprehensive guide covers all aspects of application configuration in OpenDev, from basic setup to config package generation and distribution.

Overview

App Configuration in OpenDev includes:

  • Basic application information
  • Channel and publisher bindings
  • Product configurations
  • Payment settings
  • Configuration package generation and distribution

Accessing App Configuration

  1. Log in to OpenDev Platform
  2. Go to Apps in the sidebar
  3. Click on your application
  4. Navigate using the configuration tabs

Configuration Tabs

1. Basic Info

The foundation of your application configuration.

Fields

Field Description
App Name Display name
App ID Unique identifier (read-only after creation)
App Logo Visual identifier
Platforms Target platforms (iOS, Android, Web, Desktop)
Description Internal notes
App Secrets Authentication keys per environment

Managing App Secrets

Development:  For local development
Testing:      For QA/staging environments
Production:   For live applications

Each environment has its own secret to prevent accidental production access during development.

2. Channels Tab

Configure which channels distribute your application.

Binding Channels

  1. Click Bind Channel
  2. Select from available channels
  3. Configure channel-specific settings
  4. Save bindings

Channel Settings

Setting Description
Enabled Channel is active
OAuth Providers Login methods for this channel
Payment Provider Payment processor
Region Geographic availability

Example Channel Binding

{
  "channelKey": "google_play_global",
  "enabled": true,
  "oauth": {
    "providers": ["google", "facebook"]
  },
  "payment": {
    "provider": "google_play"
  }
}

3. Products Tab

Configure products available in your application.

Product Configuration

  1. Click Add Product
  2. Select product tier to include
  3. Configure app-specific settings
  4. Save configuration

Product Settings

Setting Description
Enabled Product is purchasable
Display Order Sort order in app
Featured Highlighted in UI
Promotional Price Temporary discounts

4. Payment Tab

Configure payment processing for your application.

Payment Platforms

Enable and configure each platform:

Stripe (Web/Desktop)

{
  "platform": "stripe",
  "enabled": true,
  "publishableKey": "pk_live_xxx",
  "webhookSecret": "whsec_xxx"
}

Google Play (Android)

{
  "platform": "google_play",
  "enabled": true,
  "packageName": "com.yourcompany.app"
}

Apple (iOS)

{
  "platform": "apple",
  "enabled": true,
  "bundleId": "com.yourcompany.app"
}

WeChat Pay (China)

{
  "platform": "wechat_pay",
  "enabled": true,
  "mchId": "1234567890"
}

5. Config Packages Tab

Generate and manage configuration packages for client distribution.

Configuration Packages

What's in a Config Package?

A config package contains all client-side configuration:

{
  "app": {
    "id": "app_xxxxxxxxxxxx",
    "name": "My Application",
    "version": "1.0.0"
  },
  "channel": {
    "key": "google_play_global",
    "name": "Google Play Global"
  },
  "oauth": {
    "providers": [
      {
        "id": "google",
        "clientId": "xxxxx.apps.googleusercontent.com",
        "scopes": ["email", "profile"]
      }
    ]
  },
  "payment": {
    "enabled": true,
    "provider": "google_play"
  },
  "products": [
    {
      "id": "pro_monthly",
      "name": "Pro Monthly",
      "platformId": "pro_monthly_sub"
    }
  ],
  "services": {
    "api": "https://api.yourdomain.com",
    "cdn": "https://cdn.yourdomain.com"
  }
}

Generating Config Packages

  1. Go to Config Packages tab
  2. Click Generate Package
  3. Select configuration options:
Option Description
Channel Target distribution channel
Environment dev, test, or prod
Platform ios, android, web, or desktop
  1. Click Generate
  2. Download or copy the configuration

Package Distribution Methods

1. Direct Download

  • Download JSON file
  • Bundle with app at build time
  • Simple but requires app update for changes

2. CDN Publish

  • Publish to CDN endpoint
  • App fetches on startup
  • Update config without app release
// Client code
const configUrl = 'https://cdn.yourdomain.com/config/app_xxx/prod/android.json';
const config = await fetch(configUrl).then(r => r.json());

3. API Endpoint

  • Fetch from API at runtime
  • Most flexible
  • Requires network on startup
// Client code
const config = await api.get('/config', {
  headers: {
    'X-App-ID': appId,
    'X-Channel-Key': channelKey,
    'X-Environment': 'production'
  }
});

CDN Configuration

Setting Up CDN

  1. Go to App Details > Config Packages
  2. Click CDN Settings
  3. Configure CDN endpoint:
Field Description
CDN Provider AWS S3, Cloudflare, Aliyun OSS, etc.
Bucket/Container Storage location
Base URL Public access URL
Credentials Access keys

Publishing to CDN

  1. Generate a config package
  2. Click Publish to CDN
  3. Select target environment
  4. Confirm publication

Published configs are available at:

https://your-cdn.com/config/{appId}/{env}/{platform}.json

Version Management

Config Versioning

Each generated config gets a version:

  • Timestamp-based
  • Incrementing number
  • Can rollback if needed

Version History

  1. Go to Config Packages tab
  2. Click History
  3. View all generated configs
  4. Download or rollback to previous versions

Integration Guide

Android Integration

// Load config at startup
class ConfigManager {
    private lateinit var config: AppConfig
    
    suspend fun loadConfig() {
        val channelKey = BuildConfig.CHANNEL_KEY
        val environment = if (BuildConfig.DEBUG) "dev" else "prod"
        
        // Option 1: Bundled config
        config = loadBundledConfig()
        
        // Option 2: Remote config
        config = fetchRemoteConfig(channelKey, environment)
    }
    
    private fun loadBundledConfig(): AppConfig {
        val inputStream = context.assets.open("config.json")
        return Gson().fromJson(inputStream.reader(), AppConfig::class.java)
    }
    
    private suspend fun fetchRemoteConfig(
        channelKey: String, 
        environment: String
    ): AppConfig {
        val url = "$CDN_BASE/$APP_ID/$environment/android.json"
        return httpClient.get(url).body()
    }
}

iOS Integration

class ConfigManager {
    static let shared = ConfigManager()
    var config: AppConfig?
    
    func loadConfig() async {
        // Option 1: Bundled config
        if let bundledConfig = loadBundledConfig() {
            self.config = bundledConfig
        }
        
        // Option 2: Remote config (with fallback)
        if let remoteConfig = await fetchRemoteConfig() {
            self.config = remoteConfig
        }
    }
    
    private func loadBundledConfig() -> AppConfig? {
        guard let url = Bundle.main.url(forResource: "config", withExtension: "json"),
              let data = try? Data(contentsOf: url) else {
            return nil
        }
        return try? JSONDecoder().decode(AppConfig.self, from: data)
    }
    
    private func fetchRemoteConfig() async -> AppConfig? {
        let channelKey = Bundle.main.infoDictionary?["ChannelKey"] as? String ?? ""
        let environment = isDebug ? "dev" : "prod"
        let url = URL(string: "\(cdnBase)/\(appId)/\(environment)/ios.json")!
        
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            return try JSONDecoder().decode(AppConfig.self, from: data)
        } catch {
            return nil
        }
    }
}

Web Integration

// config.js
class ConfigManager {
  constructor() {
    this.config = null;
  }
  
  async loadConfig() {
    const channelKey = process.env.REACT_APP_CHANNEL_KEY;
    const environment = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
    
    // Try remote config first
    try {
      const url = `${CDN_BASE}/${APP_ID}/${environment}/web.json`;
      const response = await fetch(url);
      this.config = await response.json();
    } catch (error) {
      // Fallback to bundled config
      this.config = require('./config.bundled.json');
    }
    
    return this.config;
  }
  
  get(key) {
    return this.config?.[key];
  }
}

export const configManager = new ConfigManager();

Best Practices

Configuration Strategy

  1. Environment Separation
  • Never use production secrets in development
  • Separate config files per environment
  • Clear naming conventions
  1. Security
  • Don't include sensitive secrets in client config
  • Use server-side proxy for sensitive operations
  • Validate config integrity
  1. Performance
  • Cache config locally
  • Implement refresh strategy
  • Handle offline gracefully
  1. Maintainability
  • Document config changes
  • Version control config templates
  • Automate config generation in CI/CD

Config Refresh Strategy

// Recommended refresh approach
class ConfigRefreshManager {
  constructor(configManager) {
    this.configManager = configManager;
    this.refreshInterval = 3600000; // 1 hour
  }
  
  startAutoRefresh() {
    setInterval(async () => {
      try {
        const newConfig = await this.configManager.fetchRemoteConfig();
        if (this.hasChanged(newConfig)) {
          this.configManager.config = newConfig;
          this.notifyListeners();
        }
      } catch (error) {
        console.log('Config refresh failed, using cached');
      }
    }, this.refreshInterval);
  }
  
  hasChanged(newConfig) {
    return JSON.stringify(newConfig) !== JSON.stringify(this.configManager.config);
  }
}

Troubleshooting

Config Not Loading

Possible causes:

  • Network issues
  • Incorrect URL/path
  • Config not published

Solutions:

  1. Check CDN URL is correct
  2. Verify config was published
  3. Test with direct URL access
  4. Check app permissions

OAuth Not Working

Possible causes:

  • Missing OAuth config
  • Incorrect client IDs
  • Channel mismatch

Solutions:

  1. Verify OAuth providers in config
  2. Check client IDs match platform
  3. Ensure channel key is correct

Payment Issues

Possible causes:

  • Payment not enabled
  • Wrong platform config
  • Product IDs mismatch

Solutions:

  1. Verify payment enabled in config
  2. Check platform-specific settings
  3. Match product IDs with platform console