WebViewJavascriptBridge:打通iOS原生与JavaScript的通信桥梁

WebViewJavascriptBridge:打通iOS原生与JavaScript的通信桥梁

【免费下载链接】WebViewJavascriptBridge An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews 【免费下载链接】WebViewJavascriptBridge 项目地址: https://gitcode.com/gh_mirrors/we/WebViewJavascriptBridge

WebViewJavascriptBridge是iOS开发中连接原生Objective-C/Swift代码与Web页面JavaScript的重要桥梁技术,解决了移动应用开发中原生与Web技术融合的核心通信问题。本文深入探讨了该技术的项目背景、核心价值、架构设计原理、多平台支持能力以及在实际知名应用中的典型使用模式,为开发者提供全面的技术解析和实践指导。

项目背景与核心价值:为什么需要原生与Web的通信桥梁

在移动应用开发领域,原生应用与Web技术的融合已成为不可逆转的趋势。随着移动互联网的快速发展,开发者面临着既要保持原生应用性能优势,又要充分利用Web技术灵活性的双重挑战。WebViewJavascriptBridge正是在这样的背景下应运而生,它解决了iOS开发中一个长期存在的痛点:原生Objective-C/Swift代码与Web页面中JavaScript代码之间的无缝通信问题。

技术演进背景

移动应用开发经历了从纯原生到混合开发的演进过程:

mermaid

核心业务需求驱动

1. 性能与体验的平衡

原生应用虽然在性能、动画效果和系统集成方面具有优势,但存在开发周期长、跨平台兼容性差的问题。而Web技术虽然开发效率高、跨平台性好,但在复杂交互和性能敏感场景中表现不佳。WebViewJavascriptBridge让开发者能够在合适的场景选择合适的技术:

  • 原生负责:核心业务逻辑、高性能动画、硬件访问、支付安全等
  • Web负责:内容展示、活动页面、快速迭代的业务模块
2. 开发效率与维护成本

传统纯原生开发模式下,每次界面修改都需要重新编译、打包、发布,整个过程耗时且成本高昂。通过桥接技术,部分界面可以使用Web技术实现:

// 业务场景:活动页面快速上线
bridge.callHandler("showPromotionPage", {
    activityId: "202308_sale",
    theme: "summer"
}, function(response) {
    console.log("活动页面展示完成");
});
3. 动态化与热更新需求

在竞争激烈的移动互联网环境中,快速响应市场变化至关重要。WebViewJavascriptBridge支持:

  • 实时内容更新:无需发版即可更新页面内容
  • AB测试支持:快速切换不同版本的页面
  • 紧急修复:线上问题快速热修复

技术架构价值

通信机制对比
通信方式优点缺点适用场景
URL Scheme实现简单数据传输量有限简单指令传递
JavaScriptCore性能高iOS7+支持,API复杂高性能需求
WebViewJavascriptBridge平衡性好需要额外集成大多数混合场景
React Native跨平台一致学习成本高复杂跨平台应用
架构设计价值

WebViewJavascriptBridge采用了一种优雅的消息队列机制:

mermaid

这种设计确保了:

  • 线程安全:消息队列机制避免竞态条件
  • 性能优化:批量处理减少通信开销
  • 错误隔离:单次通信失败不影响整体功能
  • 向后兼容:支持多种WebView类型

实际应用场景

电商应用案例

在大型电商应用中,WebViewJavascriptBridge发挥着关键作用:

// 原生注册商品详情处理器
[self.bridge registerHandler:@"showProductDetail" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSString *productId = data[@"id"];
    ProductDetailViewController *vc = [[ProductDetailViewController alloc] initWithProductId:productId];
    [self.navigationController pushViewController:vc animated:YES];
    responseCallback(@{@"status": @"success"});
}];

// Web页面调用原生功能
bridge.callHandler("showProductDetail", {id: "12345"}, function(response) {
    if (response.status === "success") {
        console.log("成功跳转到商品详情");
    }
});
金融服务场景

金融应用对安全性和性能要求极高,桥接技术确保了:

  • 安全支付:原生处理敏感支付流程
  • 实时数据:Web展示动态行情信息
  • 风控验证:原生生物识别与Web表单结合

生态价值与行业影响

WebViewJavascriptBridge的出现不仅解决了技术问题,更重要的是推动了移动开发生态的演进:

  1. 标准化通信协议:为混合开发建立了事实标准
  2. 降低技术门槛:让更多Web开发者能够参与移动开发
  3. 促进技术融合:加速了原生与Web技术的相互借鉴和学习
  4. 丰富开发模式:支持了微前端、模块化等现代架构理念

从Facebook Messenger到众多知名应用的成功实践证明了这种架构模式的可行性和价值。在当今追求开发效率、用户体验和技术创新的多维平衡中,WebViewJavascriptBridge这样的通信桥梁技术将继续发挥不可替代的作用,推动移动应用开发向更加灵活、高效的方向发展。

WebViewJavascriptBridge架构设计解析:基础组件与工作原理

WebViewJavascriptBridge作为iOS开发中连接原生代码与JavaScript的重要桥梁,其架构设计体现了现代跨语言通信的精妙之处。该框架采用分层架构设计,将核心逻辑与平台特定实现分离,确保了代码的可维护性和扩展性。

核心架构组件

WebViewJavascriptBridge的架构主要由三个核心组件构成:

组件名称职责描述关键特性
WebViewJavascriptBridgeBase核心消息处理引擎提供消息队列管理、回调处理、URL协议识别等基础功能
WebViewJavascriptBridge平台适配层(UIWebView)处理UIWebView的特定实现,包括代理方法重写和消息转发
WKWebViewJavascriptBridge平台适配层(WKWebView)专门为WKWebView优化的实现,支持现代WebKit特性

消息通信机制

WebViewJavascriptBridge采用基于URL Scheme的异步消息传递机制,其工作流程如下:

mermaid

基础组件详细解析

1. WebViewJavascriptBridgeBase - 核心引擎

WebViewJavascriptBridgeBase是整个架构的心脏,负责管理所有的消息传递逻辑:

@interface WebViewJavascriptBridgeBase : NSObject

@property (strong, nonatomic) NSMutableArray* startupMessageQueue;
@property (strong, nonatomic) NSMutableDictionary* responseCallbacks;
@property (strong, nonatomic) NSMutableDictionary* messageHandlers;

- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName;
- (void)flushMessageQueue:(NSString *)messageQueueString;
- (BOOL)isWebViewJavascriptBridgeURL:(NSURL*)url;

@end

关键数据结构说明:

  • startupMessageQueue: 存储WebView加载完成前发送的消息
  • responseCallbacks: 管理所有待处理的回调函数,使用唯一ID进行标识
  • messageHandlers: 注册的原生处理器字典,键为处理器名称,值为处理块
2. 消息格式与协议

WebViewJavascriptBridge定义了一套完整的消息协议格式:

#define kOldProtocolScheme @"wvjbscheme"
#define kNewProtocolScheme @"https"
#define kQueueHasMessage   @"__wvjb_queue_message__"
#define kBridgeLoaded      @"__bridge_loaded__"

typedef NSDictionary WVJBMessage;

消息对象结构示例:

{
  "handlerName": "getUserInfo",
  "data": {"userId": 123},
  "callbackId": "cb_1234567890",
  "responseId": "resp_9876543210"
}
3. JavaScript端实现

JavaScript端的实现同样采用模块化设计:

window.WebViewJavascriptBridge = {
    registerHandler: registerHandler,
    callHandler: callHandler,
    disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,
    _fetchQueue: _fetchQueue,
    _handleMessageFromObjC: _handleMessageFromObjC
};

关键JavaScript函数:

  • _doSend(): 将消息加入队列并通过iframe.src触发通信
  • _fetchQueue(): 获取并清空消息队列,返回JSON字符串
  • _dispatchMessageFromObjC(): 分发从原生端接收的消息

工作原理深度剖析

消息传递流程
  1. 初始化阶段:WebView加载时注入JavaScript桥接代码
  2. 处理器注册:双方通过registerHandler方法注册消息处理器
  3. 消息发送:通过callHandler发起跨语言调用
  4. 队列管理:使用消息队列缓冲异步通信
  5. 响应处理:通过回调ID匹配请求和响应
URL Scheme拦截机制

WebViewJavascriptBridge巧妙地利用URL Scheme拦截来实现通信:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];
    if ([_base isWebViewJavascriptBridgeURL:url]) {
        // 处理桥接相关的URL请求
        return NO; // 阻止实际导航
    }
    return YES; // 允许其他URL加载
}
异步回调管理

框架采用唯一的回调ID来管理异步通信:

mermaid

性能优化策略

WebViewJavascriptBridge在设计时考虑了多种性能优化:

  1. 消息批处理:通过消息队列减少通信次数
  2. 延迟加载:WebView完成加载后再注入JavaScript代码
  3. 内存管理:及时清理已完成的回调引用
  4. 安全超时:默认启用安全超时机制防止JavaScript弹窗阻塞

这种架构设计使得WebViewJavascriptBridge能够在保持高性能的同时,提供稳定可靠的跨语言通信能力,为iOS应用与Web内容的深度集成提供了强有力的技术支撑。

支持的多平台能力:UIWebView、WKWebView和OSX WebView

WebViewJavascriptBridge作为一个成熟的跨平台通信解决方案,提供了对iOS和macOS平台上所有主要WebView类型的全面支持。这种多平台兼容性使得开发者可以在不同的应用场景中使用统一的API进行原生与JavaScript之间的通信。

平台适配架构设计

WebViewJavascriptBridge采用了智能的平台检测机制,通过预处理器宏自动识别当前编译环境,从而选择正确的WebView类型和委托协议:

#if defined __MAC_OS_X_VERSION_MAX_ALLOWED
    #define WVJB_PLATFORM_OSX
    #define WVJB_WEBVIEW_TYPE WebView
    #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject<WebViewJavascriptBridgeBaseDelegate>
    #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject<WebViewJavascriptBridgeBaseDelegate, WebPolicyDelegate>
#elif defined __IPHONE_OS_VERSION_MAX_ALLOWED
    #import <UIKit/UIWebView.h>
    #define WVJB_PLATFORM_IOS
    #define WVJB_WEBVIEW_TYPE UIWebView
    #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject<UIWebViewDelegate>
    #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject<UIWebViewDelegate, WebViewJavascriptBridgeBaseDelegate>
#endif

这种设计确保了代码的平台兼容性,开发者无需关心底层实现细节,只需使用统一的bridgeForWebView:方法即可创建桥接实例。

UIWebView支持(iOS传统方案)

UIWebView是iOS早期的Web视图组件,WebViewJavascriptBridge提供了完整的支持:

// UIWebView使用示例
UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

// 注册原生处理器
[bridge registerHandler:@"getUserInfo" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSDictionary* userInfo = @{@"name": @"张三", @"age": @25};
    responseCallback(userInfo);
}];

// 调用JavaScript处理器
[bridge callHandler:@"showNotification" data:@{@"message": @"欢迎使用"}];

UIWebView的实现基于UIWebViewDelegate协议,通过拦截shouldStartLoadWithRequest:方法来处理桥接通信。

WKWebView支持(iOS现代方案)

WKWebView是Apple推荐的现代Web视图,具有更好的性能和内存管理:

// WKWebView使用示例(需要iOS 8.0+)
WKWebView* webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

// 设置导航委托
[bridge setWebViewDelegate:self];

// 注册消息处理器
[bridge registerHandler:@"loadData" handler:^(id data, WVJBResponseCallback responseCallback) {
    // 处理数据加载逻辑
    [self loadDataFromNetwork:data completion:^(NSArray* result) {
        responseCallback(result);
    }];
}];

WKWebView的实现使用了专门的WKWebViewJavascriptBridge类,它实现了WKNavigationDelegate协议,通过JavaScriptCore框架提供更高效的通信机制。

OSX WebView支持(macOS桌面应用)

对于macOS应用程序,WebViewJavascriptBridge同样提供了完整的支持:

// macOS WebView使用示例
WebView* webView = [[WebView alloc] initWithFrame:self.view.bounds];
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

// 注册桌面特定的处理器
[bridge registerHandler:@"openFileDialog" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSOpenPanel* openPanel = [NSOpenPanel openPanel];
    [openPanel beginWithCompletionHandler:^(NSInteger result) {
        if (result == NSFileHandlingPanelOKButton) {
            responseCallback(openPanel.URL.path);
        }
    }];
}];

macOS版本的实现基于WebPolicyDelegate协议,提供了与Cocoa桌面应用环境完美集成的能力。

多平台特性对比

下表展示了不同平台WebView的支持特性对比:

特性UIWebViewWKWebViewOSX WebView
最低系统版本iOS 2.0+iOS 8.0+OS X 10.2+
内存管理较差优秀良好
性能一般优秀良好
JavaScript执行UI线程独立进程主线程
通信机制URL拦截JavaScriptCoreURL拦截
推荐使用场景旧项目维护新项目开发macOS应用

统一的API设计

尽管底层实现不同,但WebViewJavascriptBridge为所有平台提供了完全一致的API:

mermaid

这种设计使得开发者可以编写一次代码,在多个平台上运行,大大提高了开发效率。

平台特定的最佳实践

UIWebView最佳实践:

  • 适用于需要支持旧版iOS系统的应用
  • 注意内存管理,及时释放不需要的WebView实例
  • 使用disableJavscriptAlertBoxSafetyTimeout()提高通信速度

WKWebView最佳实践:

  • 新项目首选,提供更好的性能和稳定性
  • 支持更现代的JavaScript特性
  • 使用独立的进程模型,避免阻塞主线程

OSX WebView最佳实践:

  • 完美集成macOS的Native和Web技术
  • 支持丰富的桌面交互特性
  • 可以利用macOS特有的API和功能

跨平台通信机制

无论使用哪种WebView,通信机制都保持一致:

mermaid

这种统一的通信模式确保了代码的可移植性和维护性,开发者可以在不同平台间共享业务逻辑和通信协议。

WebViewJavascriptBridge的多平台支持能力使其成为iOS和macOS开发中连接Native和Web技术的首选解决方案,无论是维护旧项目还是开发新应用,都能提供稳定可靠的跨平台通信体验。

实际应用场景:知名App案例与典型使用模式

WebViewJavascriptBridge作为iOS平台最成熟的JavaScript与原生代码通信解决方案之一,已被众多知名应用程序采用。这些应用涵盖了社交、电商、工具、游戏等多个领域,充分证明了该框架的稳定性和实用性。

知名应用案例深度解析

Facebook Messenger:实时通信的桥梁

Facebook Messenger利用WebViewJavascriptBridge实现了Web内容与原生功能的深度整合。其典型使用模式包括:

消息推送处理流程: mermaid

核心功能实现代码示例:

// Objective-C端注册消息处理器
[self.bridge registerHandler:@"sendMessage" handler:^(id data, WVJBResponseCallback responseCallback) {
    Message *message = [[Message alloc] initWithData:data];
    [self.messageService sendMessage:message completion:^(NSError *error) {
        if (error) {
            responseCallback(@{@"success": @NO, @"error": error.localizedDescription});
        } else {
            responseCallback(@{@"success": @YES});
        }
    }];
}];

// JavaScript端调用原生功能
bridge.callHandler('sendMessage', {
    text: messageText,
    attachments: attachmentData,
    timestamp: Date.now()
}, function(response) {
    if (response.success) {
        showSuccessNotification();
    } else {
        showError(response.error);
    }
});
Facebook Paper:内容展示与交互优化

Facebook Paper作为创新的内容阅读应用,通过WebViewJavascriptBridge实现了:

富媒体内容加载流程: mermaid

电商类应用:Yardsale的交易体验优化

Yardsale等电商应用利用WebViewJavascriptBridge实现了Web与原生支付的完美结合:

支付流程集成:

// 注册支付处理器
[self.bridge registerHandler:@"initiatePayment" handler:^(NSDictionary *paymentData, WVJBResponseCallback responseCallback) {
    PaymentProcessor *processor = [PaymentProcessor sharedInstance];
    [processor processPaymentWithData:paymentData completion:^(PaymentResult *result) {
        responseCallback(@{
            @"status": result.status,
            @"transactionId": result.transactionId ?: [NSNull null],
            @"error": result.error ? result.error.localizedDescription : [NSNull null]
        });
    }];
}];

典型使用模式分类

模式一:数据查询与获取

设备信息获取模式:

// 获取设备信息的统一接口
class DeviceInfoService {
    static async getDeviceInfo() {
        return new Promise((resolve, reject) => {
            bridge.callHandler('getDeviceInfo', null, (response) => {
                if (response.success) {
                    resolve(response.data);
                } else {
                    reject(new Error(response.error));
                }
            });
        });
    }
}

// 使用示例
const deviceInfo = await DeviceInfoService.getDeviceInfo();
console.log('设备型号:', deviceInfo.model);
console.log('系统版本:', deviceInfo.osVersion);
模式二:原生功能调用

相机与相册访问: mermaid

实现代码:

[self.bridge registerHandler:@"takePhoto" handler:^(NSDictionary *options, WVJBResponseCallback responseCallback) {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    picker.delegate = self;
    picker.modalPresentationStyle = UIModalPresentationFullScreen;
    
    self.photoResponseCallback = responseCallback;
    [self presentViewController:picker animated:YES completion:nil];
}];

#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker 
didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey, id> *)info {
    UIImage *image = info[UIImagePickerControllerOriginalImage];
    NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
    NSString *base64String = [imageData base64EncodedStringWithOptions:0];
    
    if (self.photoResponseCallback) {
        self.photoResponseCallback(@{
            @"success": @YES,
            @"data": base64String,
            @"mimeType": @"image/jpeg",
            @"width": @(image.size.width),
            @"height": @(image.size.height)
        });
    }
    
    [picker dismissViewControllerAnimated:YES completion:nil];
}
模式三:实时事件通知

网络状态监控:

// 注册网络状态变化监听
bridge.registerHandler('networkStatusChanged', function(statusData) {
    const { isConnected, type, isExpensive } = statusData;
    
    if (!isConnected) {
        showOfflineWarning();
    } else if (isExpensive) {
        showCellularWarning();
    } else {
        hideNetworkWarnings();
    }
    
    // 更新应用状态
    AppState.network = statusData;
});
模式四:性能优化与缓存管理

图片缓存优化策略:

[self.bridge registerHandler:@"loadImage" handler:^(NSDictionary *request, WVJBResponseCallback responseCallback) {
    NSString *imageUrl = request[@"url"];
    CGSize targetSize = CGSizeMake([request[@"width"] floatValue], [request[@"height"] floatValue]);
    
    // 检查内存缓存
    UIImage *cachedImage = [ImageCache.shared imageForKey:imageUrl];
    if (cachedImage) {
        NSData *imageData = UIImageJPEGRepresentation(cachedImage, 0.8);
        responseCallback(@{@"success": @YES, @"data": [imageData base64EncodedStringWithOptions:0]});
        return;
    }
    
    // 异步下载和处理
    [ImageLoader loadImageWithURL:imageUrl targetSize:targetSize completion:^(UIImage *image, NSError *error) {
        if (image) {
            NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
            responseCallback(@{@"success": @YES, @"data": [imageData base64EncodedStringWithOptions:0]});
        } else {
            responseCallback(@{@"success": @NO, @"error": error.localizedDescription});
        }
    }];
}];

企业级应用的最佳实践

错误处理与监控

健壮的错误处理机制:

class BridgeService {
    constructor() {
        this.requestId = 0;
        this.pendingRequests = new Map();
    }

    callHandler(handlerName, data, timeout = 30000) {
        return new Promise((resolve, reject) => {
            const requestId = ++this.requestId;
            const timer = setTimeout(() => {
                this.pendingRequests.delete(requestId);
                reject(new Error('Request timeout'));
            }, timeout);

            this.pendingRequests.set(requestId, { resolve, reject, timer });

            bridge.callHandler(handlerName, data, (response) => {
                clearTimeout(timer);
                this.pendingRequests.delete(requestId);
                
                if (response.success) {
                    resolve(response.data);
                } else {
                    reject(new Error(response.error || 'Unknown error'));
                }
            });
        });
    }
}
性能监控与统计

通信性能指标收集:

// 包装原有的callHandler方法添加监控
- (void)monitoredCallHandler:(NSString *)handlerName 
                       data:(id)data 
          responseCallback:(WVJBResponseCallback)responseCallback {
    
    CFTimeInterval startTime = CACurrentMediaTime();
    
    WVJBResponseCallback monitoredCallback = ^(id responseData) {
        CFTimeInterval duration = CACurrentMediaTime() - startTime;
        
        // 记录性能指标
        [PerformanceMonitor recordBridgeCall:handlerName 
                                   duration:duration 
                                    success:responseData != nil];
        
        if (responseCallback) {
            responseCallback(responseData);
        }
    };
    
    [self callHandler:handlerName data:data responseCallback:monitoredCallback];
}

安全考虑与实践

输入验证与安全处理:

- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler {
    // 添加安全包装
    WVJBHandler safeHandler = ^(id data, WVJBResponseCallback responseCallback) {
        // 验证输入数据
        if (![self validateInputData:data forHandler:handlerName]) {
            responseCallback(@{@"success": @NO, @"error": @"Invalid input data"});
            return;
        }
        
        @try {
            handler(data, responseCallback);
        } @catch (NSException *exception) {
            responseCallback(@{@"success": @NO, @"error": exception.reason});
        }
    };
    
    [super registerHandler:handlerName handler:safeHandler];
}

通过这些实际应用案例和典型使用模式的分析,我们可以看到WebViewJavascriptBridge在大型应用中的关键作用。无论是Facebook这样的社交巨头,还是各类电商、工具应用,都依赖这一桥梁技术实现了Web技术与原生能力的完美融合,为用户提供了既丰富又流畅的移动体验。

技术总结

WebViewJavascriptBridge作为iOS平台最成熟的JavaScript与原生代码通信解决方案,已被Facebook Messenger、Facebook Paper、Yardsale等众多知名应用采用,证明了其在大型项目中的稳定性和实用性。该框架通过优雅的架构设计实现了UIWebView、WKWebView和OSX WebView的多平台支持,提供了统一的API接口和健壮的通信机制。从电商交易到社交应用,从内容展示到支付处理,WebViewJavascriptBridge在各种场景下都发挥着关键作用,为移动应用开发提供了Web技术与原生能力完美融合的解决方案,是现代混合开发架构中不可或缺的重要组件。

【免费下载链接】WebViewJavascriptBridge An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews 【免费下载链接】WebViewJavascriptBridge 项目地址: https://gitcode.com/gh_mirrors/we/WebViewJavascriptBridge

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值