前段时间有事请耽搁了,今天跟大家一起看下Google的in-app Billing V3支付。

   如果没有Google Play此处附上安装Google Play的一键安装器的链接(需要Root权限):http://www.muzhiwan.com/com.muzhiwan.gsfinstaller-86095.html

   google Play商店理应是Android发布游戏及应用最首选的平台,毕竟google Play是Google为Android应用打造的商店,但在天朝却完全不是这么回事。众所周知天朝对google的封锁一直很严密(你妹的,坑爹),逐渐形成了“翻过墙去,人人平等”的局面,咳咳,在这里只是感慨一下,绝无他意。
   之前用过Google Billing V2,感觉不太爽。V2版支付走的是异步通知,不能即时得到支付结果,支付、查询接口太过复杂,还有就是没找到Restore Order接口,因此选择使用V3版,网上大部分都是介绍Google Billing的付费机制原理,具体针对某个功能点的很模糊,所以如果大家想了解Google Billing付费机制的这篇博文大可不看,网上转载多的是,我写这篇博文的目的是想让大家快速的将Google支付集成到自己项目中。
   集成Google in-app Billing的前提是你已经正确连接上VPN(大陆用户),基本上每个公司都会有VPN的,这个找项目组长去要。
   也正式由于天朝的封锁使得在大陆接Google的支付加大了难度。所以要想接in-app Billing首先要有一个稳定的vpn,PS:非大陆的就行,最好是美、日的。
   VPN设置:

注意:类型根据VPN而定,我用的是L2TP/IPSec PSK,选择此类型时,编辑只需填写名称,服务器地址和IPSec预共享密钥即可,然后连接的时候填写帐号和密码。当打开Google商店能看到付费软件表名VPN已成功连接,如果显示VPN已连接但还看不到付费软件时,进入应用程序管理器分别清除Google Play服务和Google Play商店数据之后再打开Google商店即可。


   注:源码导入工程是不可用的,需将包名、版本号、版本code、签名改为你上传至Google控制台测试应用的包名、版本号、版本code、签名,且将MainActivity.java中的String base64EncodedPublicKey = "";填写上你应用程序的签名。PS:签名即Eclipse->Android Tools->Export Signed Application Package...
    网盘分享中的DemoForGoogleBilling.apk文件是可支付的,但支付会将钱打到我们公司账户上,因为我用的是上线app的key。

一:接入流程:
    1.申请Google开发者帐号,开发人员控制台左侧选择“设置”填写测试人员帐号。
    2.添加新应用,此处有个“上传APK”,此处上传的apk上传到Bate版或者ALPHA版,但包名、版本code、版本name、签名需跟最终上线的产品保持一致。此处上传测试版本的目的是当你支付接入完毕后测试时用。

    3.集成Google Billing。
      (1).Purchasing Items,购买商品时的通信过程

       (2).Consuming In-app Products,消耗产品时的通信过程

    4.测试支付。
       (1).测试支付官方文档链接http://developer.android.com/google/play/billing/billing_testing.html
       (2).Testing with static responses,静态测试,即当支付状态为一下四种情况时游戏逻辑是否正确。
官方给出的4种如下:
There are four reserved product IDs for testing static In-app Billing responses:
android.test.purchased
When you make an In-app Billing request with this product ID, Google Play responds as though you successfully purchased an item. The response includes a JSON string, which contains fake purchase information (for example, a fake order ID). In some cases, the JSON string is signed and the response includes the signature so you can test your signature verification implementation using these responses.
android.test.canceled
When you make an In-app Billing request with this product ID Google Play responds as though the purchase was canceled. This can occur when an error is encountered in the order process, such as an invalid credit card, or when you cancel a user's order before it is charged.
android.test.refunded
When you make an In-app Billing request with this product ID, Google Play responds as though the purchase was refunded. Refunds cannot be initiated through Google Play's in-app billing service. Refunds must be initiated by you (the merchant). After you process a refund request through your Google Wallet merchant account, a refund message is sent to your application by Google Play. This occurs only when Google Play gets notification from Google Wallet that a refund has been made. For more information about refunds, see Handling IN_APP_NOTIFY messages and In-app Billing Pricing.
android.test.item_unavailable
When you make an In-app Billing request with this product ID, Google Play responds as though the item being purchased was not listed in your application's product list.
       例:当配置为android.test.purchased时:mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”, RC_REQUEST, mPurchaseFinishedListener);

       (3).当游戏逻辑测试通过后,进行支付测试。测试时手机设备上绑定的Google帐号必须是在开发者控制台中配置的测试帐号,绑定非大陆的信用卡,支付后会在开发者控制台看到支付的订单,由于是测试订单,可以将测试产生的费用返还给绑定的信用卡。
      测试效果图如下(由于本人没有非大陆的信用卡,所以只能看到这个界面,上线项目“蘑菇帮”测试ok)

支付接入过程中涉及到的接口及名词:

一:受管理商品和不受管理商品

    1.受管理商品即不可重复购买的,例如:解锁关卡,激活游戏等。
    2.不受管理商品即可重复购买的,例如:购买金币,购买药水,等消耗品。
    3.订阅商品,由于项目中没有涉及到,如有需要的可以翻阅一下Google Billing文档。
Google in-app Billing V3将所有商品默认为受管理的,如果有不受管理商品则需要调用consumeAsync去消耗调,(或者你可以通俗的理解为,当你成功购买一个道具,Google后台会将此道具加上标记,当你调用consumeAsync将订单消耗掉时,该订单标记被取消)。
二:三个回调

1.IabHelper.OnIabPurchaseFinishedListener  支付完成的回调,如果是受管理的商品在此回调中直接可以将道具给用户

2.IabHelper.OnConsumeFinishedListener  消耗完成的回调,当不受管理的商品被成功消耗进入此回调,此时将不受管理的商品给用户

3.IabHelper.QueryInventoryFinishedListener  查询完成的回调,Restore Order的时候用,当有订单成功付款但由于种种原因(突然断网、断电等)没收到Google支付成功的回调时,在这里可以查询到此订单,此时需要对订单进行处理(给用户道具等)。

四:测试用的app一定要跟上传到Google的测试版的包名、版本code、name、签名一致,否则无法进行支付测试。

1.当签名不一致或者版本code、版本name不一致时错误界面如下:

2.当包名不一致时错误界面如下:

接下来跟大家一起看一下代码具体实现:
1.下载in-app-billing-v03,下载地址:http://pan.baidu.com/share/link?shareid=1387554851&uk=473193131将下载后的压缩包解压:

将src目录下两个包及包中的java文件引入工程,例如:

2.添加权限:<uses-permission android:name="com.android.vending.BILLING" />

3.添加支付代码:
   初始化IapHelper:

String base64EncodedPublicKey = "";此处填写Google控制台添加新应用程序后的appid

mHelper = new IabHelper(this, base64EncodedPublicKey);

// enable debug logging (for a production application, you should set this to false).

mHelper.enableDebugLogging(false);

// Start setup. This is asynchronous and the specified listener

// will be called once setup completes.

Log.d(TAG, "Starting setup.");

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {

public void onIabSetupFinished(IabResult result) {

Log.d(TAG, "Setup finished.");

if (!result.isSuccess()) {

// Oh noes, there was a problem.

complain("Problem setting up in-app billing: " + result);

return;

}

iap_is_ok = true;

// Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.

Log.d(TAG, "Setup successful. Querying inventory.");

}

});

调用支付接口:

if (iap_is_ok) {

mHelper.launchPurchaseFlow(MainActivity.this, skus[1], RC_REQUEST, mPurchaseFinishedListener);

}else {

showMessage("提示", "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");

}

调用查询接口:

mHelper.queryInventoryAsync(mGotInventoryListener);

调用获取道具价格接口:(因Google市场是根据不同国家显示不同货币价格,所以显示到游戏道具列表中的价格不是定值,而是动态获取的)

billingservice = mHelper.getService();

Bundle querySkus = new Bundle();

querySkus.putStringArrayList("ITEM_ID_LIST", skus);

try {

Bundle skuDetails = billingservice.getSkuDetails(3, MainActivity.this.getPackageName(),"inapp", querySkus);

ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");

if (null!=responseList) {

for (String thisResponse : responseList) {

try {

SkuDetails d = new SkuDetails(thisResponse);

for (int i = 0; i < sku_list.size(); i++) {

if (sku_list.get(i).equals(d.getSku())) {

price_list.set(i, d.getPrice());

}

}

iapHandler.sendEmptyMessage(0);

} catch (JSONException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

} catch (RemoteException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

三个回调:

// Callback for when a purchase is finished

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {

public void onIabPurchaseFinished(IabResult result, Purchase purchase) {

Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);

if (result.isFailure()) {

// Oh noes!

complain("Error purchasing: " + result);

return;

}

Log.d(TAG, "Purchase successful.");

if (purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")) {

mHelper.consumeAsync(purchase, mConsumeFinishedListener);

}else if (purchase.getSku().equals("double_income")) {

//受管理的商品,开启双倍经验

showMessage("支付成功", "成功购买双倍经验");

}

}

};

// Called when consumption is complete

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {

public void onConsumeFinished(Purchase purchase, IabResult result) {

Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);

// We know this is the "gas" sku because it's the only one we consume,

// so we don't check which sku was consumed. If you have more than one

// sku, you probably should check...

if (result.isSuccess()) {

// successfully consumed, so we apply the effects of the item in our

// game world's logic, which in our case means filling the gas tank a bit

if (purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")) {

showMessage("支付成功", "成功购买100猫币");

}

}

else {

complain("Error while consuming: " + result);

}

}

};

// Listener that's called when we finish querying the items we own

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {

public void onQueryInventoryFinished(IabResult result, Inventory inventory) {

Log.d(TAG, "Query inventory finished.");

if (result.isFailure()) {

complain("Failed to query inventory: " + result);

return;

}

Log.d(TAG, "Query inventory was successful.");

if (inventory.hasPurchase("double_income")) {

//查询到有受管理的商品支付成功需要将道具给用户

showMessage("成功Restore双倍金币", "查询到有双倍金币需要恢复");

}else if(inventory.hasPurchase("cions_100")){

//查询到不受管理的商品支付成功需要将道具消耗掉

showMessage("成功Restore100金币","查询到有100金币需要恢复" );

}

}

};

处理返回Activity后的数据:

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// TODO Auto-generated method stub

Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);

// Pass on the activity result to the helper for handling

if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {

// not handled, so handle it ourselves (here's where you'd

// perform any handling of activity results not related to in-app

// billing...

super.onActivityResult(requestCode, resultCode, data);

}

else {

Log.d(TAG, "onActivityResult handled by IABUtil.");

}

}

退出游戏后销毁IabHelper:

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

if (mHelper != null) mHelper.dispose();

mHelper = null;

}

最后附上MainActivity.java完整文件,源码下载地址:http://pan.baidu.com/share/link?shareid=1579953623&uk=473193131

package cn.catcap.together;

import java.util.ArrayList;

import org.json.JSONException;

import com.android.vending.billing.IInAppBillingService;

import com.example.android.trivialdrivesample.util.IabHelper;

import com.example.android.trivialdrivesample.util.IabResult;

import com.example.android.trivialdrivesample.util.Inventory;

import com.example.android.trivialdrivesample.util.Purchase;

import com.example.android.trivialdrivesample.util.SkuDetails;

import android.os.Bundle;

import android.os.Handler;

import android.os.RemoteException;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.Intent;

import android.util.Log;

import android.view.View;

import android.widget.TextView;

public class MainActivity extends Activity {

// The helper object

IabHelper mHelper;

// Debug tag, for logging

static final String TAG = "TrivialDrive";

// Current amount of gas in tank, in units

int mTank;

// (arbitrary) request code for the purchase flow请求码

static final int RC_REQUEST = 10001;

private boolean iap_is_ok = false;

//double_income为受管理商品,coins_100为不受管理商品

private String[] skus = {"android.test.purchased","double_income","coins_100"};

private ArrayList<String> sku_list;

private ArrayList<String> price_list;

private IInAppBillingService billingservice;

private TextView tv;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

String base64EncodedPublicKey = "";//此处填写自己的appid

mHelper = new IabHelper(this, base64EncodedPublicKey);

// enable debug logging (for a production application, you should set this to false).

mHelper.enableDebugLogging(false);

// Start setup. This is asynchronous and the specified listener

// will be called once setup completes.

Log.d(TAG, "Starting setup.");

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {

public void onIabSetupFinished(IabResult result) {

Log.d(TAG, "Setup finished.");

if (!result.isSuccess()) {

// Oh noes, there was a problem.

complain("Problem setting up in-app billing: " + result);

return;

}

iap_is_ok = true;

// Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.

Log.d(TAG, "Setup successful. Querying inventory.");

}

});

//购买双倍金币(受管理商品)

findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

iapHandler.sendEmptyMessage(1);

}

});

//购买100猫币(不受管理商品)

findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

iapHandler.sendEmptyMessage(2);

}

});

//Restore Order

findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if (iap_is_ok) {

mHelper.queryInventoryAsync(mGotInventoryListener);

}else {

showMessage("提示", "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");

}

}

});

//获取价格

findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

sku_list = new ArrayList<String>();

price_list = new ArrayList<String>();

//添加默认值

sku_list.add("double_income");

price_list.add("HK$40");

sku_list.add("coins_100");

price_list.add("HK$8");

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

getPrice();

}

}).start();

}

});

//测试订单

findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

iapHandler.sendEmptyMessage(3);

}

});

//显示价格

tv = (TextView) findViewById(R.id.text);

}

//获取价格

private void getPrice(){

ArrayList<String> skus = new ArrayList<String>();

skus.add("double_income");

skus.add("coins_100");

billingservice = mHelper.getService();

Bundle querySkus = new Bundle();

querySkus.putStringArrayList("ITEM_ID_LIST", skus);

try {

Bundle skuDetails = billingservice.getSkuDetails(3, MainActivity.this.getPackageName(),"inapp", querySkus);

ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");

if (null!=responseList) {

for (String thisResponse : responseList) {

try {

SkuDetails d = new SkuDetails(thisResponse);

for (int i = 0; i < sku_list.size(); i++) {

if (sku_list.get(i).equals(d.getSku())) {

price_list.set(i, d.getPrice());

}

}

iapHandler.sendEmptyMessage(0);

} catch (JSONException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

} catch (RemoteException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

Handler iapHandler = new Handler(){

public void handleMessage(android.os.Message msg) {

switch(msg.what){

case 0:

tv.setText(price_list.get(0)+"\n"+price_list.get(1));

break;

case 1:

if (iap_is_ok) {

mHelper.launchPurchaseFlow(MainActivity.this, skus[1], RC_REQUEST,           mPurchaseFinishedListener);

}else {

showMessage("提示", "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");

}

break;

case 2:

if (iap_is_ok) {

mHelper.launchPurchaseFlow(MainActivity.this, skus[2], RC_REQUEST, mPurchaseFinishedListener);

}else {

showMessage("提示", "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");

}

break;

case 3:

if (iap_is_ok) {

mHelper.launchPurchaseFlow(MainActivity.this, skus[0], RC_REQUEST, mPurchaseFinishedListener);

}else {

showMessage("提示", "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");

}

break;

default:

break;

}

};

};

// Callback for when a purchase is finished

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {

public void onIabPurchaseFinished(IabResult result, Purchase purchase) {

Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);

if (result.isFailure()) {

// Oh noes!

complain("Error purchasing: " + result);

return;

}

Log.d(TAG, "Purchase successful.");

if (purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")) {

mHelper.consumeAsync(purchase, mConsumeFinishedListener);

}else if (purchase.getSku().equals("double_income")) {

//受管理的商品,开启双倍经验

showMessage("支付成功", "成功购买双倍经验");

}

}

};

// Called when consumption is complete

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {

public void onConsumeFinished(Purchase purchase, IabResult result) {

Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);

// We know this is the "gas" sku because it's the only one we consume,

// so we don't check which sku was consumed. If you have more than one

// sku, you probably should check...

if (result.isSuccess()) {

// successfully consumed, so we apply the effects of the item in our

// game world's logic, which in our case means filling the gas tank a bit

if (purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")) {

showMessage("支付成功", "成功购买100猫币");

}

}

else {

complain("Error while consuming: " + result);

}

}

};

// Listener that's called when we finish querying the items we own

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {

public void onQueryInventoryFinished(IabResult result, Inventory inventory) {

Log.d(TAG, "Query inventory finished.");

if (result.isFailure()) {

complain("Failed to query inventory: " + result);

return;

}

Log.d(TAG, "Query inventory was successful.");

if (inventory.hasPurchase("double_income")) {

//查询到有受管理的商品支付成功需要将道具给用户

showMessage("成功Restore双倍金币", "查询到有双倍金币需要恢复");

}else if(inventory.hasPurchase("cions_100")){

//查询到不受管理的商品支付成功需要将道具消耗掉

showMessage("成功Restore100金币","查询到有100金币需要恢复" );

}

}

};

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// TODO Auto-generated method stub

Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);

// Pass on the activity result to the helper for handling

if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {

// not handled, so handle it ourselves (here's where you'd

// perform any handling of activity results not related to in-app

// billing...

super.onActivityResult(requestCode, resultCode, data);

}

else {

Log.d(TAG, "onActivityResult handled by IABUtil.");

}

}

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

if (mHelper != null) mHelper.dispose();

mHelper = null;

}

void complain(String message) {

Log.e(TAG, "**** TrivialDrive Error: " + message);

alert("Error: " + message);

}

void alert(String message) {

AlertDialog.Builder bld = new AlertDialog.Builder(this);

bld.setMessage(message);

bld.setNeutralButton("OK", null);

Log.d(TAG, "Showing alert dialog: " + message);

bld.create().show();

}

private void showMessage(String title,String message){

new AlertDialog.Builder(MainActivity.this).setTitle(title).setMessage(message).setPositiveButton("确定", null).show();

}

}

以上就是完整的Google in-app Billing接入过程,接下来会跟大家一起走一遍亚马逊支付,如有疑问请留言。

Android支付接入(七):Google In-app-Billing的更多相关文章

  1. Android支付接入之Google In-app-Billing

    原文链接:http://www.mobile-open.com/2016/966337.html 因为公司需要接入Google的应用内支付(即Google的in-app Billing V3),接入过 ...

  2. Android支付接入(7):Google In-app-Billing

    今天跟大家一起看下Google的in-app Billing V3支付.    如果没有GooglePlay此处附上安装Google Play的一键安装器的链接(需要Root权限):http://ww ...

  3. Android支付接入(五):机锋网

    原地址:http://blog.csdn.net/simdanfeg/article/details/9012083 前边已经陆续跟大家走了一遍运营商和支付宝付费接入,今天跟大家一起看看机锋网的支付接 ...

  4. Android支付接入(四):联通VAC计费

    原地址:http://blog.csdn.net/simdanfeg/article/details/9012031 注意事项: 1.联通支付是不需要自己标识软硬计费点的,当平台申请计费点的时候会提交 ...

  5. Android支付接入(三):电信爱游戏支付

    原地址:http://blog.csdn.net/simdanfeg/article/details/9011977 注意事项: 1.电信要求必须先启动电信的闪屏界面 2.非网络游戏不允许有Inter ...

  6. Android支付接入(二):移动游戏基地

    原地址:http://blog.csdn.net/simdanfeg/article/details/9011863 上篇博文跟大家一起走了一遍支付宝支付,今天我们来看看移动支付.众所周知目前付费通道 ...

  7. Android支付接入(一):支付宝

    原地址:http://blog.csdn.net/simdanfeg/article/details/9011603 转载之前我想深深地感谢屌丝哥 相信相同过App获取利润的都会需要接入计费SDK,下 ...

  8. Android支付接入(八):Amazon亚马逊支付

    下面跟大家一起走一遍Amazon亚马逊的支付,亚马逊目前刚把业务拓展到大陆市场,但这并不代表Amazon支付不成熟,恰恰相反,Amazon的支付流程,支付结果获取及测试另人称赞,支付流程.测试流程简洁 ...

  9. Android Q 接入 MQTT

    Android Q 接入 MQTT 首先在APP 下引入mqtt的库 implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1 ...

随机推荐

  1. asp.net2.0安全性(1)--用户角色篇(起篇)--转载来自车老师

    安全管理的解决方案在.net1.1中几乎为一片空白,对于应用程序的验证与授权大部分的工作是开发人员自己编写代码,或者是借助企业库等工具来实现,此可谓.net1.1中的一大缺憾.在.net2.0中微软为 ...

  2. mac下brew install 报错

    mac下brew install 报错 错误提示: 原因:是这个brew的权限不正确 修改一下这个brew的权限 chown root:wheel /usr/local/bin/brew

  3. 基于visual Studio2013解决面试题之0503取最大数字字符串

     题目

  4. Boost::asio io_service 实现分析

    io_service的作用 io_servie 实现了一个任务队列,这里的任务就是void(void)的函数.Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run ...

  5. javascript 中对this关键字的一些理解

    var self = this 可能会觉得奇怪为什么我会定义一个_self的变量, 因为在js里,this不用对于其他的对象语言,他的解析过程与运行过程中this会改变的.这里简单说说js里this的 ...

  6. HBase数据存储格式

    好的数据结构,对于检索数据,插入数据的效率就会很高. 常见的数据结构 B+树 根节点和枝节点非常easy,分别记录每一个叶子节点的最小值,并用一个指针指向叶子节点.  叶子节点里每一个键值都指向真正的 ...

  7. 炮塔郝梦主solo

    尊重开发人员的工作,转载时请注明出处:http://blog.csdn.net/haomengzhu/article/details/31885287 或许你会由于它爱上dota: 或许你会由于它爱上 ...

  8. 后台调用外部程序的完美实现(使用CreateDesktop建立隐藏桌面)

    最近在做的一个软件,其中有一部分功能需要调用其它的软件来完成,而那个软件只有可执行文件,根本没有源代码,幸好,我要做的事不难,只需要在我的程序启动后,将那个软件打开,在需要的时候,对其中的一个文本矿设 ...

  9. HDOJ 2442 -bricks 状态压缩DP 一直TLE.打表过的..

    有5个砖块..加上一个空着不放..那么有6种状态..所以很明显的可以用6进制的状态DP... 不过这么做..我觉得我已经能优化的都优化了...还是超时..一看数据范围是100*6..打表先AC了.. ...

  10. Android手机便携式wifi的使用及无线数据传输(主要针对XP系统)

    适用条件: 1.可以上网的安卓系统2.2以上的智能手机,或有便携式wifi功能的安卓智能手机 2.有无线网卡的笔记本电脑或台式机(特别是XP系统) 测试手机:中兴U930 电脑:华硕K50系列笔记本 ...