www.example.com, and configure the origin server to the COS where the Android APK parent package is located, as shown below:
const CUSTOM_BLOCK_VALUE_LENGTH = 10240;const APK_SIGNING_BLOCK_MAGIC_LENGTH = 16;const APK_SIGNING_BLOCK_OFFSET_LENGTH = 8;const APK_COMMENT_LENGTH = 512;class EdgePack {totalSize;signVersion;centralDirectoryOffset;customBlockValueStart;customBlockValueEnd;rangeRelativeOffset;customInfo;constructor() {this.totalSize = null;this.signVersion = null;this.centralDirectoryOffset = null;this.customBlockValueStart = null;this.customBlockValueEnd = null;this.rangeRelativeOffset = null;this.customInfo = null;}async handle(event) {const { request } = event;const headers = new Headers(request.headers);const modifiedRequest = new Request(request, { headers });if (!this.checkRequest(modifiedRequest)) {return;}let response = null;try {const headRequest = new Request(modifiedRequest.url, {method: 'HEAD',headers: modifiedRequest.headers,});response = await fetch(headRequest);} catch (err) {const error = {code: 'FETCH_ORIGIN_ERROR',message: err?.message,};response = new Response(JSON.stringify(error), {status: 590,});}if (!this.checkResponse(response)) {return event.respondWith(response);}response.headers.set('Cache-Control', 'max-age=0');const streamResponse = new Response(await this.combineStreams(modifiedRequest),response);event.respondWith(streamResponse);}getRelativeOffset(response) {const start = this.customBlockValueStart;const end = this.customBlockValueEnd;const range = response.headers.get('Content-Range');if (!range) return start;const match = range.match(/bytes\\s*(\\d*)-(\\d*)/i);if (!match || match?.length < 2) {return start;}if (+match[2] < start || +match[1] > end) {return null;}return start - +match[1];}checkRequest(request) {if (request.method !== 'GET') {return false;}if (request.headers.has('Range')) {return false;}const { pathname, searchParams } = new URL(request.url);const comment = searchParams?.get('comment');if (!pathname.endsWith('.apk') || !comment) {return false;}this.customInfo = comment;return true;}checkResponse(response) {if (response.status !== 200 && response.status !== 206) {return false;}const contentLength = response.headers.get('Content-Length');if (response.body === null || contentLength === null) {return false;}this.totalSize = Number(contentLength);const cosOffsetHeader = response.headers.get('x-cos-meta-edgepack-offset');const cosTypeHeader = response.headers.get('x-cos-meta-edgepack-type');if (!cosOffsetHeader || !cosTypeHeader) {return false;}this.signVersion = cosTypeHeader;this.centralDirectoryOffset = Number(cosOffsetHeader);if (this.signVersion === 'v1') {this.customBlockValueStart = this.totalSize - APK_COMMENT_LENGTH;this.customBlockValueEnd = this.totalSize;} else {this.customBlockValueStart =this.centralDirectoryOffset -CUSTOM_BLOCK_VALUE_LENGTH -APK_SIGNING_BLOCK_MAGIC_LENGTH -APK_SIGNING_BLOCK_OFFSET_LENGTH;this.customBlockValueEnd = this.centralDirectoryOffset;}this.rangeRelativeOffset = this.getRelativeOffset(response);if (this.rangeRelativeOffset === null) {return false;}return true;}async combineStreams(request) {const { readable, writable } = new TransformStream();this.handleStream(request, writable);return readable;}async handleStream(request, writable) {const comment = this.customInfo;const relativeOffset = this.rangeRelativeOffset;const encoder = new TextEncoder();const section = encoder.encode(comment);try {const apkHeader = await this.apkHeaderStream(request);try {await apkHeader.pipeTo(writable, {preventClose: true,});} catch (e) {console.error('HEADER_STREAM_ERROR: ', e);}// Return to Blob dataconst apkBody = await this.apkBodyStream(request,section,relativeOffset);const apkBodyStream = apkBody.stream();try {await apkBodyStream.pipeTo(writable, {preventClose: true,});} catch (e) {console.error('BODY_STREAM_ERROR: ', e);}const apkTail = await this.apkTailStream(request);try {await apkTail.pipeTo(writable, {preventClose: true,});} catch (e) {console.error('TAIL_STREAM_ERROR: ', e);}} catch (err) {console.error('HANDLE_STREAM_ERROR: ', err);} finally {let writer = writable.getWriter();writer.close();writer.releaseLock();}}async apkHeaderStream(request) {const headers = new Headers(request.headers);headers.set('Range', `bytes=0-${this.customBlockValueStart - 1}`);//Obtaining the part before the signature block.const headResponse = await fetch(request, {headers: headers,});return headResponse.body;}async apkBodyStream(request, section = null, relativeOffset = 0) {const headers = new Headers(request.headers);headers.set('Range',`bytes=${this.customBlockValueStart}-${this.customBlockValueEnd - 1}`);const middleResponse = await fetch(request, {headers: headers,});const reader = middleResponse.body.getReader();let outputBuffers = [];try {let handledBytes = this.customBlockValueStart;while (true) {const result = await reader.read();if (result.done) {console.log('APK_BODY_STREAM_DONE');break;}const startByteOffset = handledBytes;const buffer = result.value;handledBytes += buffer.byteLength;const min = Math.max(startByteOffset, relativeOffset);const max = Math.min(relativeOffset + section.byteLength, handledBytes);if (min < max) {const bufferStart = min - startByteOffset;const sectionStart = min - relativeOffset;const sectionEnd = max - relativeOffset;const replacement = section.subarray(sectionStart, sectionEnd);new Uint8Array(buffer).set(replacement, bufferStart);}outputBuffers.push(buffer);}} catch (err) {console.error('APK_BODY_STREAM_ERROR: ', err);}return new Blob(outputBuffers);}async apkTailStream(request) {const headers = new Headers(request.headers);headers.set('Range',`bytes=${this.customBlockValueEnd}-${this.totalSize - 1}`);const tailResponse = await fetch(request, {headers: headers,});return tailResponse.body;}}async function handleEvent(event) {const edgepack = new EdgePack();await edgepack.handle(event);}addEventListener('fetch', handleEvent);

www.example.com with a file suffix of .apk, it will trigger the edge function for dynamic packaging.http://www.example.com/v2_src.apk?comment=test. This will trigger the edge function to dynamically inject the channel information into the specified location. In this case, "comment" is the channel parameter defined in the Creation of the Edge Function for Injecting Channel Information. Using the v2-VasDolly method as an example, you can use the VasDolly tool to read the dynamically injected channel information.

Feedback