Chapter 03 Manifest File Explained

Haiyue
17min

Chapter 3: Manifest File Explained

Learning Objectives
  1. Deeply understand the various configuration items in manifest.json
  2. Master permission declarations and security configuration
  3. Understand the differences between Manifest V2 and V3

Knowledge Summary

Manifest File Overview

The Manifest file is the configuration file for Chrome Extensions, defining the extension’s metadata, permissions, resources, and behavior. It is a required file for every extension and is located in the extension’s root directory.

Manifest Version Evolution

🔄 正在渲染 Mermaid 图表...

Manifest V3 Core Configuration

Basic Information Fields

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "version_name": "v1.0.0",
  "description": "This is a powerful Chrome extension",
  "short_name": "MyExt",
  "author": "Developer Name",
  "icons": {
    "16": "icons/icon-16.png",
    "32": "icons/icon-32.png",
    "48": "icons/icon-48.png",
    "128": "icons/icon-128.png"
  }
}

Configuration Explanation:

  • manifest_version: Required, version number (recommended to use 3)
  • name: Required, extension name
  • version: Required, version number
  • description: Extension description (maximum 132 characters)
  • short_name: Short name (maximum 12 characters)
  • author: Author information
  • version_name: User-friendly version identifier
  • icons: Mapping of icon sizes and paths

Action Configuration (formerly Browser Action)

Action Configuration Examples

Simple Popup:

{
  "action": {
    "default_popup": "popup.html",
    "default_title": "Click to open extension"
  }
}

Multiple Icon Sizes:

{
  "action": {
    "default_icon": {
      "16": "icons/icon-16.png",
      "24": "icons/icon-24.png",
      "32": "icons/icon-32.png"
    },
    "default_title": "My Extension"
  }
}

Icon Only (No Popup):

{
  "action": {
    "default_icon": "icon.png",
    "default_title": "Click to trigger background event"
  }
}

Permission System Explained

Permission Types and Declarations

Permission Categories

Basic Permissions:

  • activeTab - Access the current active tab
  • tabs - Access all tab information
  • storage - Use storage API
  • contextMenus - Add context menu items
  • notifications - Display notifications
  • alarms - Timers
  • clipboardRead - Read clipboard
  • clipboardWrite - Write to clipboard

Advanced Permissions:

  • bookmarks - Access bookmarks
  • history - Access browsing history
  • downloads - Manage downloads
  • management - Manage other extensions
  • cookies - Access cookies
  • webRequest - Intercept network requests
  • webRequestBlocking - Block network requests
  • proxy - Control proxy settings
  • debugger - Use debugger API

Host Permissions:

  • <all_urls> - Access all websites
  • *://*.google.com/* - Specific domain
  • https://*/ - All HTTPS websites
  • file:///* - Local files

Permission Configuration Example:

{
  "permissions": ["storage", "tabs"],
  "optional_permissions": ["bookmarks", "downloads"],
  "host_permissions": ["https://*.example.com/*"]
}

Permission Best Practices

1. Principle of Least Privilege - Only request necessary permissions

{
  "permissions": ["storage", "activeTab"],
  "optional_permissions": ["downloads", "bookmarks"]
}

2. Dynamic Permission Requests - Request optional permissions at runtime

// Request optional permissions
chrome.permissions.request({
    permissions: ['bookmarks'],
    origins: ['https://www.example.com/']
}, (granted) => {
    if (granted) {
        // Permission granted
        console.log('Permission granted');
    } else {
        // User denied
        console.log('Permission denied');
    }
});

3. Permission Checks - Check permissions before use

// Check permissions
chrome.permissions.contains({
    permissions: ['bookmarks'],
    origins: ['https://www.example.com/']
}, (result) => {
    if (result) {
        // Has permission
        performAction();
    } else {
        // Request permission
        requestPermission();
    }
});

Content Security Policy (CSP)

CSP Configuration Examples

Default CSP (Strictest):

{
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  }
}

Allow WASM:

{
  "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
  }
}

Sandbox Page CSP:

{
  "content_security_policy": {
    "sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
  }
}

CSP Violation Event Handling:

// Listen for CSP violation events
document.addEventListener('securitypolicyviolation', (e) => {
    console.error('CSP violation:', {
        blockedURI: e.blockedURI,
        violatedDirective: e.violatedDirective,
        originalPolicy: e.originalPolicy,
        sourceFile: e.sourceFile,
        lineNumber: e.lineNumber
    });

    // Report violation to background
    chrome.runtime.sendMessage({
        type: 'csp_violation',
        details: {
            uri: e.blockedURI,
            directive: e.violatedDirective
        }
    });
});

Background Scripts Configuration

Service Worker (Manifest V3)

Manifest V3 Uses Service Worker:

{
  "background": {
    "service_worker": "background.js",
    "type": "module"
  }
}

Service Worker Example Code:

// background.js - Service Worker

// Extension installation event
chrome.runtime.onInstalled.addListener((details) => {
    console.log('Extension installed:', details);

    // Execute different operations based on installation reason
    switch(details.reason) {
        case 'install':
            console.log('First installation');
            // Set default values
            chrome.storage.local.set({
                installed: true,
                version: chrome.runtime.getManifest().version
            });
            break;
        case 'update':
            console.log('Extension update');
            // Execute migration logic
            migrateData(details.previousVersion);
            break;
        case 'chrome_update':
            console.log('Chrome update');
            break;
    }
});

// Listen for messages from content scripts
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log('Message received:', request, 'from:', sender);

    // Async handling
    (async () => {
        try {
            const result = await handleMessage(request, sender);
            sendResponse({success: true, data: result});
        } catch (error) {
            sendResponse({success: false, error: error.message});
        }
    })();

    return true; // Keep message channel open
});

// Listen for tab updates
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo.status === 'complete') {
        console.log('Tab loaded:', tab.url);
    }
});

// Scheduled tasks
chrome.alarms.create('periodicTask', {
    periodInMinutes: 30  // Execute every 30 minutes
});

chrome.alarms.onAlarm.addListener((alarm) => {
    if (alarm.name === 'periodicTask') {
        performPeriodicTask();
    }
});

// Service Worker lifecycle
self.addEventListener('activate', (event) => {
    console.log('Service Worker activated');
});

// Handle fetch events (only needed in specific scenarios)
self.addEventListener('fetch', (event) => {
    // Can intercept and modify network requests
    console.log('Fetch event:', event.request.url);
});

async function handleMessage(request, sender) {
    // Message handling logic
    switch(request.type) {
        case 'GET_DATA':
            return await getData(request.key);
        case 'SAVE_DATA':
            return await saveData(request.key, request.value);
        default:
            throw new Error('Unknown message type');
    }
}

async function performPeriodicTask() {
    // Periodically executed task
    console.log('Executing periodic task');
}

Content Scripts Configuration

Content Script Injection Configuration

Static Declaration Method:

{
  "content_scripts": [
    {
      "matches": ["*://*.example.com/*"],
      "js": ["content.js"],
      "css": ["content.css"],
      "run_at": "document_end",
      "all_frames": false,
      "match_about_blank": false,
      "world": "ISOLATED"
    }
  ]
}

Injection Timing Options:

  • document_start - When DOM construction begins (earliest)
  • document_end - When DOM construction completes (default)
  • document_idle - When page is idle or after DOM completes

Execution Environment Options (V3):

  • ISOLATED - Isolated environment (default, has its own global scope)
  • MAIN - Main world (shares global scope with page)

Dynamic Injection Example:

// Dynamically inject content script
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
    chrome.scripting.executeScript({
        target: {tabId: tabs[0].id},
        files: ['content.js']
    });

    // Or inject CSS
    chrome.scripting.insertCSS({
        target: {tabId: tabs[0].id},
        files: ['content.css']
    });

    // Or inject function
    chrome.scripting.executeScript({
        target: {tabId: tabs[0].id},
        func: injectedFunction,
        args: ['arg1', 'arg2']
    });
});

function injectedFunction(arg1, arg2) {
    console.log('Injected function executed:', arg1, arg2);
    // This function will execute in the page context
}

Advanced Matching Patterns:

Include Specific Paths:

["*://example.com/path/*"]

Exclude Specific Pages:

{
  "matches": ["*://example.com/*"],
  "exclude_matches": ["*://example.com/admin/*"]
}

Using Glob Patterns:

{
  "matches": ["*://example.com/*"],
  "include_globs": ["*://example.com/user/*"],
  "exclude_globs": ["*://example.com/*/private/*"]
}

Manifest V2 vs V3 Differences

Major Differences Comparison

FeatureManifest V2Manifest V3Notes
Background Scriptbackground: { scripts: ['bg.js'], persistent: false }background: { service_worker: 'sw.js' }V3 uses Service Worker instead of background page
Host Permissionspermissions: ['<all_urls>']host_permissions: ['<all_urls>']V3 separates host permissions into a separate field
Action APIbrowser_action or page_actionaction (unified)V3 unifies to action API
Web Request APIFull blocking webRequestdeclarativeNetRequest (declarative)V3 restricts blocking network requests
Content Security PolicyCan use unsafe-evalProhibits unsafe-eval (except WASM)V3 strengthens security restrictions
Remote CodeCan load remote codeProhibits remote code executionV3 requires all code packaged in extension

Manifest V2 to V3 Migration Guide

1. Update manifest_version

// V2
"manifest_version": 2

// V3
"manifest_version": 3

2. Migrate Background Script

// V2 - background.js
chrome.browserAction.onClicked.addListener(() => {
    // Handle click
});

// V3 - service-worker.js
chrome.action.onClicked.addListener(() => {
    // Handle click
});

3. Update Permission Declarations

// V2
{
    "permissions": [
        "tabs",
        "https://example.com/*"
    ]
}

// V3
{
    "permissions": ["tabs"],
    "host_permissions": ["https://example.com/*"]
}

4. Replace Web Request API

// V2 - Using webRequest
chrome.webRequest.onBeforeRequest.addListener(
    (details) => {
        return {cancel: true};
    },
    {urls: ["*://example.com/*"]},
    ["blocking"]
);

// V3 - Using declarativeNetRequest
chrome.declarativeNetRequest.updateDynamicRules({
    addRules: [{
        id: 1,
        priority: 1,
        action: {type: "block"},
        condition: {urlFilter: "example.com"}
    }]
});

5. Handle Service Worker Lifecycle

// V3 - Service Worker will automatically sleep
// Use chrome.storage instead of global variables
let data; // ❌ Avoid using

// ✅ Use storage
chrome.storage.local.set({data: value});
chrome.storage.local.get(['data'], (result) => {
    // Use data
});

Complete Manifest Example

Production Project Configuration

Complete Manifest V3 Configuration Example:

{
  "manifest_version": 3,
  "name": "Advanced Chrome Extension",
  "version": "2.0.0",
  "description": "Feature-complete Chrome extension example",
  "author": "Your Name",

  "icons": {
    "16": "icons/icon-16.png",
    "32": "icons/icon-32.png",
    "48": "icons/icon-48.png",
    "128": "icons/icon-128.png"
  },

  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": {
      "16": "icons/icon-16.png",
      "32": "icons/icon-32.png"
    },
    "default_title": "Click to view options"
  },

  "background": {
    "service_worker": "background/service-worker.js",
    "type": "module"
  },

  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content/content.js"],
      "css": ["content/content.css"],
      "run_at": "document_idle",
      "all_frames": false
    }
  ],

  "permissions": [
    "storage",
    "tabs",
    "notifications",
    "alarms",
    "contextMenus"
  ],

  "optional_permissions": [
    "bookmarks",
    "history",
    "downloads"
  ],

  "host_permissions": [
    "https://*/*",
    "http://localhost/*"
  ],

  "options_page": "options/options.html",

  "web_accessible_resources": [
    {
      "resources": ["images/*.png", "styles/*.css"],
      "matches": ["<all_urls>"]
    }
  ],

  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },

  "commands": {
    "_execute_action": {
      "suggested_key": {
        "default": "Ctrl+Shift+Y",
        "mac": "Command+Shift+Y"
      },
      "description": "Open extension popup"
    },
    "toggle-feature": {
      "suggested_key": {
        "default": "Ctrl+Shift+U"
      },
      "description": "Toggle feature switch"
    }
  },

  "minimum_chrome_version": "88",
  "default_locale": "en"
}

Configuration Validation Script:

// Validate Manifest configuration
async function validateManifest() {
    const manifest = chrome.runtime.getManifest();

    console.log('Manifest validation:');
    console.log('- Version:', manifest.version);
    console.log('- Permissions:', manifest.permissions);
    console.log('- Host permissions:', manifest.host_permissions);

    // Check required fields
    const required = ['manifest_version', 'name', 'version'];
    const missing = required.filter(field => !manifest[field]);

    if (missing.length > 0) {
        console.error('Missing required fields:', missing);
        return false;
    }

    // Check version format
    const versionPattern = /^\d+\.\d+\.\d+$/;
    if (!versionPattern.test(manifest.version)) {
        console.error('Invalid version format:', manifest.version);
        return false;
    }

    console.log('✅ Manifest validation passed');
    return true;
}

validateManifest();
Important Notes
  1. Version Compatibility: Ensure target Chrome version supports the APIs used
  2. Permission Requests: Follow the principle of least privilege, avoid excessive requests
  3. Security Policy: Strictly adhere to CSP rules to ensure extension security
  4. Migration Plan: V2 extensions need to migrate to V3 as soon as possible

Chapter Summary

This chapter provided in-depth coverage of Chrome Extension Manifest file configuration:

  1. Basic Configuration: Mastered required fields and basic information setup
  2. Permission System: Understood permission types and request strategies
  3. Background Scripts: Learned Service Worker configuration methods
  4. Content Scripts: Understood content script injection configuration
  5. Version Differences: Compared major differences between V2 and V3
  6. Migration Guide: Mastered migration methods from V2 to V3

The next chapter will cover detailed development of Content Scripts.

Categories