我的文章讲过:(0085)iOS开发之OC与JS交互高级用法(JavaScriptCore)

前言:我们知道OC 在UIWebView 加载 H5中,常常需要OC 与 H5 之间进行交互调用。采取的方法有:

  1. WebViewJavascriptBridge
  2. JavaScriptCore 框架
  3. 拦截URL

特征:都通过一种中间人进行桥接实现相互调用的。

今天讲的:Flutter与原生OC、Java的交互通信 也是一种桥接的方式实现的。类似WebViewJavascriptBridge、JavaScriptCore的方式。Flutter 提供了 platform channels ,来和管理你的 Flutter view 的 ViewController 通信和交互数据。平台管道本质上是一个异步通信机制,桥接了 Dart 代码和宿主 ViewController,以及它运行于的 iOS 框架。你可以用平台管道来执行一个原生的函数,或者是从设备的传感器中获取数据。

本文翻译自官方文档:Writing custom platform-specific code

platform channel:平台通道
host;主机(这里指iOS 安卓端代码)
client:客户端(这里指Flutter端代码)

译文:

编写自定义特定平台代码(自定义平台:这里指iOS、安卓)

本指南介绍如何编写特定于平台的自定义代码。某些特定平台的功能可以通过现有的软件包获得;请参见using packages。

Flutter使用一个灵活的系统,允许您在Android平台上使用Java或Kotlin代码调用平台特定API,或者在Objective-C或Swift代码上调用iOS。

Flutter平台特定的API支持不依赖代码生成,而是依赖灵活的消息传递风格:

  • 应用程序的flutter部分通过平台通道向其host(这个应用程序的iOS、Android部分)发送消息。
  • host通过平台通道监听并接收消息。然后,它使用native programming language调用任意数量特定平台的API,同时向client(应用程序的flutter部分)发送响应。

⚠️:如果您需要在Java/Kotlin/Objective-C or Swift中使用对应平台的APIs or libraries,本指南将使用平台通道机制来说明。但您也可以通过查看defaultTargetPlatform属性,在你的Flutter app中编写特定平台的Dart代码。Platform adaptations 在这个框架中Flutter自动帮我们做了一些特定平台的适配。

体系结构概述:平台通道

消息通过平台通道在the client (UI) and host (platform) 之间传递,如图所示:

消息和响应是异步传递的,以确保用户界面保持响应。

⚠️注意:即使flutter异步地向Dart发送消息和从Dart接受消息,每当调用通道方法时,必须在平台的主线程上调用该方法。有关更多信息,请参阅线程部分。

On the client side, MethodChannel (API) 能发送message 并能响应方法回调,On the platform side,在Android 的(API)MethodChannel 和iOS的(API) FlutterMethodChannel能接收到方法调用并返回一个结果。这些类允许您用很少的“样板”代码开发平台插件。

补充:如果需要,方法调用也可以反向发送消息,用平台充当客户端在Dart中实现方法。快速动作插件quick_actions就是一个具体的例子。

平台通道数据类型支持和编解码器

标准平台通道使用标准消息编解码器,该编解码器支持对类似于JSON的简单值(booleans, numbers, Strings, byte buffers, and List and Maps)进行有效的二进制序列化(有关详细信息,请参阅StandardMessageCodec编解码器)。当发送和接收值时,这些值与消息之间的序列化和反序列化将自动进行。

下表显示了如何在平台侧接收Dart值,反之亦然:

示例:使用平台通道调用特定平台iOS和Android的代码

下面代码演示如何调用特定平台的API来取回并显示当前电池电量。它通过平台消息的一个消息getBatteryLevel()来使用Android BatteryManager API和ios device.batteryLevel API实现的。

该示例将特定平台的代码添加到主应用程序本身中。如果您想为多个应用程序重用特定平台的代码,那么项目创建步骤略有不同(请参见开发包),但是平台通道代码仍然是以相同的方式编写的。

注意:这个例子的完整的可运行源代码(Android with Java and iOS with Objective-C)可以在/examples/platform_channel/找到。For iOS with Swift, see /examples/platform_channel_swift/。

Step 1: 创建一个新工程

这里我已经有一个工程hello,跳过此步。

Step 2:创建Flutter客户端平台
  • 首先,使用一个带有返回电池电量的a single platform method 来构造通道。

通道的客户端和主机端通过通道构造函数中传递的通道名称连接。单个应用程序中使用的所有频道名称必须是唯一的;在频道名称前面加上唯一的“域前缀”,例如:samples.flutter.dev/battery

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class MethodChannelTestViewState extends State<MethodChannelTestView> {static const platform = const MethodChannel('samples.flutter.dev/battery');// Get battery level.
}
  • 接着,封装一个方法_getBatteryLevel(),在这个方法中用上面的通道对象platform调用invokeMethod来调用一个字符串标识符为getBatteryLevel一个具体方法。这个方法在特定平台实现。调用可能会失败,例如,如果平台不支持platform API(例如在模拟器中运行时),因此请将invokeMethod调用包装在try catch语句中。

用返回的结果来更新setstate内电池级别的用户界面状态。

  // Get battery level.String _batteryLevel = 'Unknown battery level.';Future<void> _getBatteryLevel() async {String batteryLevel;try {final int result = await platform.invokeMethod('getBatteryLevel');batteryLevel = 'Battery level at $result % .';} on PlatformException catch (e) {batteryLevel = "Failed to get battery level: '${e.message}'.";}setState(() {_batteryLevel = batteryLevel;});}
  • 最后,替换模板中的build方法,以包含一个以字符串形式显示电池状态的
    用户界面,以及一个用于刷新值的按钮。
@override
Widget build(BuildContext context) {return Material(child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [RaisedButton(child: Text('Get Battery Level'),onPressed: _getBatteryLevel,),Text(_batteryLevel),],),),);
}

Step 3a 使用Objective-C添加iOS特定平台的实现

注意:以下步骤使用Objective-C。如果您喜欢使用Swift,请跳到步骤4b。
首先在Xcode中打开flutter应用程序的iOS主机部分:

  1. 找到Flutter项目文件夹hello->ios->Runner.xcworkspace 用Xcode打开。
  2. 打开 AppDelegate.m
  • [1] copy 下面代码并替换AppDelegate.m对应代码
#import <Flutter/Flutter.h>
#import "GeneratedPluginRegistrant.h"@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;FlutterMethodChannel* batteryChannel = [FlutterMethodChannelmethodChannelWithName:@"samples.flutter.dev/battery"binaryMessenger:controller];[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {// Note: this method is invoked on the UI thread.// TODO}];[GeneratedPluginRegistrant registerWithRegistry:self];return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
  • [2] 接下来,添加使用iOS电池API检索电池电量的OC代码。此代码与您在本机iOS应用程序中编写的代码完全相同。
    AppDelegate类中@end之前添加以下方法:
- (int)getBatteryLevel {UIDevice* device = UIDevice.currentDevice;device.batteryMonitoringEnabled = YES;if (device.batteryState == UIDeviceBatteryStateUnknown) {return -1;} else {return (int)(device.batteryLevel * 100);}
}
  • [3] 最后来完善前面添加的setMethodCallHandler()方法。您需要处理调用getBatteryLevel()以此来测试返回的值,并使用result参数返回成功和错误情况的响应。如果调用了未知的方法,请报告该方法:unknown method is called
__weak typeof(self) weakSelf = self
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {// Note: this method is invoked on the UI thread.if ([@"getBatteryLevel" isEqualToString:call.method]) {int batteryLevel = [weakSelf getBatteryLevel];if (batteryLevel == -1) {result([FlutterError errorWithCode:@"UNAVAILABLE"message:@"Battery info unavailable"details:nil]);} else {result(@(batteryLevel));}} else {result(FlutterMethodNotImplemented);}
}];

完成:您现在应该可以在iOS上运行该应用程序了。如果使用iOS模拟器,请注意它不支持电池API,并且应用程序显示“电池信息不可用”。

效果如下:这样就实现了Flutter与原生OC的通信。为了更好的验证。我还增加了一个方法getFromOCClientMessage

最后附上flutter 、OC端的完整代码

flutter:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';class MethodChannelTest extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn MethodChannelTestView();}
}class MethodChannelTestView extends StatefulWidget {@overrideState<StatefulWidget> createState() {// TODO: implement createStatereturn MethodChannelTestViewState();}
}class MethodChannelTestViewState extends State <MethodChannelTestView> {static const platform = const MethodChannel('samples.flutter.dev/battery');final textColorStyle = TextStyle(color: Colors.deepOrange);// Get battery level.String _batteryLevel = 'Unknown battery level.';// 测试从OC 端传过来的字符串String _messageFromOC = '默认Flutter';Future<void> _getBatteryLevel() async {String batteryLevel;try {final int result = await platform.invokeMethod('getBatteryLevel');batteryLevel = 'Battery level at $result % .';} on PlatformException catch (e) {batteryLevel = "Failed to get battery level: '${e.message}'.";}print(batteryLevel);setState(() {_batteryLevel = batteryLevel;});}// 测试Flutter 与OC 端通信Future<void> _getFromOCClientMessage () async {String message;try {final String result = await platform.invokeMethod('getFromOCClientMessage');message = 'Message 来自 $result % .';} on PlatformException catch (e) {message = "Failed to get Message: '${e.message}'.";}print('我获取到从OC 传过来的值 :$message');setState(() {_messageFromOC = message;});}void _pushSaved() {print('你哈后!');}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text('我的收藏列表'),actions: <Widget>[new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),],),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[RaisedButton(child: Text('Get Battery Level'),onPressed: _getBatteryLevel,),Text(_batteryLevel,style: textColorStyle),SizedBox(height: 40,),RaisedButton(child: Text('Get Message From OC'),onPressed: _getFromOCClientMessage,),Text(_messageFromOC,style: textColorStyle,),],),),);}
}

OC 端代码:

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {FlutterViewController *controller = (FlutterViewController *)self.window.rootViewController;FlutterMethodChannel *batteryChannel = [FlutterMethodChannelmethodChannelWithName:@"samples.flutter.dev/battery"binaryMessenger:controller];__weak typeof(self) weakSelf = self;[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {// Note: this method is invoked on the UI thread.if ([@"getBatteryLevel" isEqualToString:call.method]){int batteryLevel = [weakSelf getBatteryLevel];if (batteryLevel == -1) {result([FlutterError errorWithCode:@"UNAVAILABLE" message:@"Battery info unavailable" details:nil]);} else {result(@(batteryLevel));}} else if ([@"getFromOCClientMessage" isEqualToString:call.method])  {NSString *testMethod = [weakSelf getFromOCClientMessage];result(testMethod);} else {result(FlutterMethodNotImplemented);}}];[GeneratedPluginRegistrant registerWithRegistry:self];return [super application:application didFinishLaunchingWithOptions:launchOptions];
}- (int)getBatteryLevel {UIDevice* device = UIDevice.currentDevice;device.batteryMonitoringEnabled = YES;if (device.batteryState == UIDeviceBatteryStateUnknown) {return -1;} else {return (int)(device.batteryLevel * 100);}
}- (NSString *)getFromOCClientMessage {return @"我来自OC client!!!";
}@end

Step 3b 使用swift添加iOS平台特定的实现

不再翻译和Step 4a 相同。只是改用swift语法实现即可。

Step 4a 使用Java添加Android平台特定的实现

同理:

  1. 找到Flutter项目文件夹hello->Android 用Android Studio打开。
  2. 打开 MainActivity.java
  • [1] copy 下面代码并替换MainActivity.java对应代码
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;public class MainActivity extends FlutterActivity {private static final String CHANNEL = "samples.flutter.dev/battery";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall call, Result result) {// Note: this method is invoked on the main thread.// TODO}});}
}
  • [2] 接下来,添加使用Android电池API检索电池电量的java代码。此代码与您在本机Android应用程序中编写的代码完全相同。
    首先,在文件顶部添加所需的导入:
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
  • [3] 然后将以下内容作为新方法添加到Activity类中onCreate()方法下面:
private int getBatteryLevel() {int batteryLevel = -1;if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);} else {Intent intent = new ContextWrapper(getApplicationContext()).registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);}return batteryLevel;
}
  • [4]最后来完善前面添加的setMethodCallHandler()方法。您需要处理调用getBatteryLevel()以此来测试返回的值,并使用result参数返回成功和错误情况的响应。如果调用了未知的方法,请报告该方法:unknown method is called
@Override
public void onMethodCall(MethodCall call, Result result) {// Note: this method is invoked on the main thread.if (call.method.equals("getBatteryLevel")) {int batteryLevel = getBatteryLevel();if (batteryLevel != -1) {result.success(batteryLevel);} else {result.error("UNAVAILABLE", "Battery level not available.", null);}} else {result.notImplemented();}
}

最后附上flutter 、Java端的完整代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';class MethodChannelTest extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn MethodChannelTestView();}
}class MethodChannelTestView extends StatefulWidget {@overrideState<StatefulWidget> createState() {// TODO: implement createStatereturn MethodChannelTestViewState();}
}class MethodChannelTestViewState extends State <MethodChannelTestView> {static const platform = const MethodChannel('samples.flutter.dev/battery');final textColorStyle = TextStyle(color: Colors.deepOrange);// Get battery level.String _batteryLevel = 'Unknown battery level.';// 测试从OC 端传过来的字符串String _messageFromOC = '默认Flutter';// 测试从AD 端传过来的字符串String _messageFromAD = '默认Flutter';Future<void> _getBatteryLevel() async {String batteryLevel;try {final int result = await platform.invokeMethod('getBatteryLevel');batteryLevel = 'Battery level at $result % .';} on PlatformException catch (e) {batteryLevel = "Failed to get battery level: '${e.message}'.";}print(batteryLevel);setState(() {_batteryLevel = batteryLevel;});}// 测试Flutter 与OC 端通信Future<void> _getFromOCClientMessage () async {String message;try {final String result = await platform.invokeMethod('getFromOCClientMessage');message = 'Message 来自 $result % .';} on PlatformException catch (e) {message = "Failed to get Message: '${e.message}'.";}print('我获取到从OC 传过来的值 :$message');setState(() {_messageFromOC = message;});}// 测试Flutter 与AD 端通信Future<void> _getFromADClientMessage () async {String message;try {final String result = await platform.invokeMethod('getFromADClientMessage');message = 'Message 来自 $result % .';} on PlatformException catch (e) {message = "Failed to get Message: '${e.message}'.";}print('我获取到从AD 传过来的值 :$message');setState(() {_messageFromAD = message;});}void _pushSaved() {print('你哈后!');}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text('我的收藏列表'),actions: <Widget>[new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),],),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[RaisedButton(child: Text('Get Battery Level'),onPressed: _getBatteryLevel,),Text(_batteryLevel,style: textColorStyle),SizedBox(height: 40,),RaisedButton(child: Text('Get Message From OC'),onPressed: _getFromOCClientMessage,),Text(_messageFromOC,style: textColorStyle,),SizedBox(height: 40,),RaisedButton(child: Text('Get Message From Andriod'),onPressed: _getFromADClientMessage,),Text(_messageFromAD,style: textColorStyle,),],),),);}
}

Java 端

package com.example.hello;import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.util.Log;public class MainActivity extends FlutterActivity {private static final String CHANNEL = "samples.flutter.dev/battery";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodCallHandler() {public void onMethodCall(MethodCall call, Result result) {String method = call.method;//Log.d(method, "The onStart() event");if (call.method.equals("getBatteryLevel")) {int batteryLevel = getBatteryLevel();if (batteryLevel != -1) {result.success(batteryLevel);} else {result.error("UNAVAILABLE", "Battery level not available.", null);}} else if (call.method.equals("getFromADClientMessage"))  {String message = getFromADClientMessage();result.success(message) ;} else {result.notImplemented();}}});GeneratedPluginRegistrant.registerWith(this);}private int getBatteryLevel() {int batteryLevel = -1;if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);} else {Intent intent = new ContextWrapper(getApplicationContext()).registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);}return batteryLevel;}private String getFromADClientMessage() {return "我来自Android";}
}

效果如图:

Flutter与原生OC、Java的交互通信大结局

完成了Flutter与原生OC、Java的交互通信!???!

Flutter开发Flutter与原生OC、Java的交互通信-1(47)相关推荐

  1. Flutter开发Flutter与原生OC、Java的交互通信-2(48)

    我们上一篇主要讲了Flutter与原生OC.Java的交互通信的机制:平台通道 只实现了Flutter 主动调用OC.Java的方向的通信.并没有实现OC.Java端主动调用Flutter的实现.这里 ...

  2. React Native开发指南-在原生和React Native间通信

    通过植入原生应用和原生UI组件两篇文档,我们学习了React Native和原生组件的互相整合.在整合的过程中,我们会需要在两个世界间互相通信.有些方法已经在其他的指南中提到了,这篇文章总结了所有可行 ...

  3. flutter开发欠揍♎

    最近很火的就是flutter 所以我也是心血来潮的去看了一下,不看不要紧 一看都是坑 ,开发前奏真的很欠揍,所以整理了一下开发前需要做的事. flutter开发需要Android Studio模拟器, ...

  4. 阿衰java免费版_flutter plugin之路:flutter与原生交互传值OC/java版(一)

    说在前头:flutter虽然很牛掰,但是目前很多功能或者插件的实现其实还是需要通过原生来实现,然后通过flutter和原生的交互传值实现数据的交换. -本篇是flutter调用原生方法,然后原生执行完 ...

  5. Flutter开发使用PlatformView显示iOS原生View(50)

    我们在使用Flutter开发跨平台开发移动APP时,会遇到Flutter的组件满足不了原生的效果,部分控件不如原生控件好用时,就想在Flutter 的Widget 中使用iOS原生View来组合实现良 ...

  6. 邂逅Flutter开发

    邂逅Flutter开发 一.Flutter是什么? 1.1 Flutter 文档链接 二.Flutter的特点 2.1 美观: 2.2 快速: 2.3 高效: 2.4 开放: 三.平台独立开发 四.跨 ...

  7. Flutter开发相比React-Native优势在哪里?高手为你答疑解惑!

    移动开发领域变化太快,如今越来越多的跨平台移动开发框架问世,对原生的冲击越来越大.React-Native,weex等移动开发框架非常火热,却也都有不少问题,其中最让人不满意的就是性能问题了.但是,假 ...

  8. Flutter开发之认识Flutter(一)

    内容来自:Flutter中文网 Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面. Flutter可以与现有的代码一起工作.在全世界,Flutter正在被 ...

  9. 【Flutter】开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

    文章目录 一.Flutter 包和插件简介 二.创建 Flutter 插件 1.Android Studio 中可视化创建 2.命令行创建 三.创建 Dart 包 1.Android Studio 中 ...

最新文章

  1. linux命令之高级使用 find
  2. 孙宇晨大战Vitalik
  3. 利用Word2010给汉字添加汉语拼音
  4. 禁止复制粘贴_网页禁止复制粘贴? 教你5招, 绕过网页限制, 免费复制全网内容!...
  5. gcc support java_由于CC寻找不存在的gcc版本,自制软件无法安装公式
  6. “科班出身”的程序员和“培训出身”的程序员的大型辩论(甩锅)现场
  7. windows快速打开命令窗口方式[利刃篇]
  8. mysql bit类型_Mysql:bit类型的查询与插入
  9. Maven 梳理 - Maven中的dependencyManagement 意义
  10. Vuex getters 基础使用
  11. php获取当月的天数,php获取当月的天数及上月第一天和最后一天等数据 - YangJunwei...
  12. Node.js入门(含NVM、NPM、NVM的安装)-(转载)
  13. 初级软考程序员科目一考什么内容?
  14. M1芯片的Mac在开发iOS项目时遇到的问题汇总(模拟器无法运行,Cocoapods错误等)
  15. mysql blast2go_blast2go本地化教程
  16. openwrt系统理解
  17. 如何用计算机解开op手机密码,oppo清除锁屏密码【操作技巧】
  18. 20162316刘诚昊 第三周学习总结
  19. 分布式人工智能:基于TensorFlow RTOS与群体智能体系(文末留言赠书)
  20. PHP Rewrite (重写)

热门文章

  1. C++ 基本数据类型
  2. 精读《Function VS Class 组件》
  3. SFB 项目经验-51-某上市企业2千人Exchange 2013升级2016高可用之伤01
  4. shell转换特殊的格式(%b)到时间戳  08/Dec/2016
  5. Jrebel6.3.3破解,配置图文教程
  6. 【SQL Server】系统学习之三:逻辑查询处理阶段-六段式
  7. Linux shell编程学习实例与参数分析(一)
  8. 处理程序“WebServiceHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
  9. 【异步编程】Part3:取消异步操作
  10. Spring中-IOC-Bean的初始化-循环依赖的解决