最近公司弄Ionic框架,项目中需要微信支付,无奈,把我调过去弄,期间也是几近崩溃,好在皇天不负有心人,在看别人的文档,终于是在项目中集成了微信支付,下面作为一个小白的我,想要把我的经验分享给大家,希望对大家有所帮助。
先给一个可用的demo吧(运行前先看txt文件)
http://download.csdn.net/detail/simon_crystin/9699743;
(温馨提示:大家下载下来可能会出错,也有可能不会。下面给出出错的解决方法:1.进入项目中的WeIXinPay->Build Path->configure build path,移除那个报错的jar包。 2.会出现资源找不到的情况,这是因为你没有v7包,下载一个v7包,或者把出错的地方都删除,只是一个主题,删除了看起来不好看而已,当然,你也可以用你有的主题。 还有一个问题需要提出来,就是你可能按照里面的text操作的仍然调不起客户端,有可能是你没有安装微信客户端,因为我没有做判断。这个demo不会出现只能成功支付一次的情况,博主亲测有效。出现只能支付一次只能说明你的签名没有对应)

1.去微信开放平台申请微信支付服务,绑定自己的应用这里具体不多讲,但是一定要申请完成,将会得到是三个参数

  //appid 微信分配的公众账号IDpublic static final String APP_ID = "";//商户号 微信分配的公众账号IDpublic static final String MCH_ID = "";//  API密钥,在商户平台设置public static final  String API_KEY= "";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

**坑点提示:在微信开发平台设置包名和签名。这里的包名一定要和你自己的包名一样,就是manifest中的package,签名一定要和你用官方app生成的一样(https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)。
微信会根据你的填写的包名,然后对你的keystore进行一种算法,生成你的签名。包名和签名一定要和微信开放平台的相同。不过这里需要注意的是,如果你发布的正式版本,需要用官方app重新生成签名,然后在开放平台重新设置sign,因为测试版本的keystore与正式版的keystore不一样。总之,就是你用的keystore生成的sign要和微信开放平台的时刻保持一致。**

2.准备工作做好了,接下来就是开发了,先下载微信的jar包,导入。
微信支付分为三个步骤
1.生成prepayId

@Overrideprotected Map<String, String> doInBackground(String... params) {// TODO Auto-generated method stubString url=String.format(params[0]);String entity=getProductArgs();Log.e("Simon",">>>>"+entity);byte[] buf=Util.httpPost(url, entity);String content = new String(buf);Log.e("orion", "----"+content);Map<String,String> xml=decodeXml(content);return xml;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.生成签名参数

private void genPayReq() {req.appId = Constants.APP_ID;req.partnerId = Constants.MCH_ID;if (resultunifiedorder!=null) {req.prepayId = resultunifiedorder.get("prepay_id");req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");}else {Toast.makeText(MainActivity.this, "prepayid为空", Toast.LENGTH_SHORT).show();}req.nonceStr = getNonceStr();req.timeStamp = String.valueOf(genTimeStamp());List<NameValuePair> signParams = new LinkedList<NameValuePair>();signParams.add(new BasicNameValuePair("appid", req.appId));signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));signParams.add(new BasicNameValuePair("package", req.packageValue));signParams.add(new BasicNameValuePair("partnerid", req.partnerId));signParams.add(new BasicNameValuePair("prepayid", req.prepayId));signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));req.sign = genAppSign(signParams);sb.append("sign\n"+req.sign+"\n\n");textView.setText(sb.toString());Log.e("Simon", "----"+signParams.toString());}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

3.调起支付。

/** 调起微信支付*/private void sendPayReq() {msgApi.registerApp(Constants.APP_ID);msgApi.sendReq(req);Log.i(">>>>>", req.partnerId);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
下面给出完整代码
package com.alpha.live;import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.xmlpull.v1.XmlPullParser;import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
/*** Created by Simon on 2016/12/2.*/
public class MainActivity extends Activity implements OnClickListener {private Button submitButton;private Button confirmButton;private TextView textView;private StringBuffer sb;private Map<String,String> resultunifiedorder;private PayReq req;private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);submitButton=(Button) findViewById(R.id.bt_submit_order);confirmButton=(Button) findViewById(R.id.bt_corfirm);textView=(TextView) findViewById(R.id.tv_prepay_id);submitButton.setOnClickListener(this);confirmButton.setOnClickListener(this);sb=new StringBuffer();req=new PayReq();}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.bt_submit_order:String urlString="https://api.mch.weixin.qq.com/pay/unifiedorder";PrePayIdAsyncTask prePayIdAsyncTask=new PrePayIdAsyncTask();prePayIdAsyncTask.execute(urlString);      //生成prepayIdbreak;case R.id.bt_corfirm:genPayReq();//生成签名参数sendPayReq();//调起支付break;default:break;}}/** 调起微信支付*/private void sendPayReq() {msgApi.registerApp(Constants.APP_ID);msgApi.sendReq(req);Log.i(">>>>>", req.partnerId);}private long genTimeStamp() {return System.currentTimeMillis() / 1000;}private void genPayReq() {req.appId = Constants.APP_ID;req.partnerId = Constants.MCH_ID;if (resultunifiedorder!=null) {req.prepayId = resultunifiedorder.get("prepay_id");req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");}else {Toast.makeText(MainActivity.this, "prepayid为空", Toast.LENGTH_SHORT).show();}req.nonceStr = getNonceStr();req.timeStamp = String.valueOf(genTimeStamp());List<NameValuePair> signParams = new LinkedList<NameValuePair>();signParams.add(new BasicNameValuePair("appid", req.appId));signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));signParams.add(new BasicNameValuePair("package", req.packageValue));signParams.add(new BasicNameValuePair("partnerid", req.partnerId));signParams.add(new BasicNameValuePair("prepayid", req.prepayId));signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));req.sign = genAppSign(signParams);sb.append("sign\n"+req.sign+"\n\n");textView.setText(sb.toString());Log.e("Simon", "----"+signParams.toString());}private String genAppSign(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();for (int i = 0; i < params.size(); i++) {sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());sb.append('&');}sb.append("key=");sb.append(Constants.API_KEY);this.sb.append("sign str\n"+sb.toString()+"\n\n");String appSign = MD5.getMessageDigest(sb.toString().getBytes());Log.e("Simon","----"+appSign);return appSign;}private class PrePayIdAsyncTask extends AsyncTask<String,Void, Map<String, String>>{private ProgressDialog dialog;@Overrideprotected void onPreExecute() {// TODO Auto-generated method stubsuper.onPreExecute();dialog = ProgressDialog.show(MainActivity.this, "提示", "正在提交订单");}@Overrideprotected Map<String, String> doInBackground(String... params) {// TODO Auto-generated method stubString url=String.format(params[0]);String entity=getProductArgs();Log.e("Simon",">>>>"+entity);byte[] buf=Util.httpPost(url, entity);String content = new String(buf);Log.e("orion", "----"+content);Map<String,String> xml=decodeXml(content);return xml;}@Overrideprotected void onPostExecute(Map<String, String> result) {// TODO Auto-generated method stubsuper.onPostExecute(result);if (dialog != null) {dialog.dismiss();}sb.append("prepay_id\n"+result.get("prepay_id")+"\n\n");textView.setText(sb.toString());resultunifiedorder=result;}}public Map<String,String> decodeXml(String content) {try {Map<String, String> xml = new HashMap<String, String>();XmlPullParser parser = Xml.newPullParser();parser.setInput(new StringReader(content));int event = parser.getEventType();while (event != XmlPullParser.END_DOCUMENT) {String nodeName=parser.getName();switch (event) {case XmlPullParser.START_DOCUMENT:break;case XmlPullParser.START_TAG:if("xml".equals(nodeName)==false){//实例化student对象xml.put(nodeName,parser.nextText());}break;case XmlPullParser.END_TAG:break;}event = parser.next();}return xml;} catch (Exception e) {Log.e("Simon","----"+e.toString());}return null;}private String getProductArgs() {// TODO Auto-generated method stubStringBuffer xml=new StringBuffer();try {String nonceStr=getNonceStr();xml.append("<xml>");List<NameValuePair> packageParams=new LinkedList<NameValuePair>();packageParams.add(new BasicNameValuePair("appid",Constants.APP_ID));packageParams.add(new BasicNameValuePair("body", "APP pay test"));packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));packageParams.add(new BasicNameValuePair("notify_url", "https://www.baidu.com"));//写你们的回调地址packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo()));packageParams.add(new BasicNameValuePair("total_fee", "1"));packageParams.add(new BasicNameValuePair("trade_type", "APP"));String sign=getPackageSign(packageParams);packageParams.add(new BasicNameValuePair("sign", sign));String xmlString=toXml(packageParams);return xmlString;} catch (Exception e) {// TODO: handle exceptionreturn null;}}//生成订单号,测试用,在客户端生成private String genOutTradNo() {Random random = new Random();
//      return "dasgfsdg1234"; //订单号写死的话只能支付一次,第二次不能生成订单return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}//生成随机号,防重发private String getNonceStr() {// TODO Auto-generated method stubRandom random=new Random();return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}/**生成签名*/private String getPackageSign(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();for (int i = 0; i < params.size(); i++) {sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());sb.append('&');}sb.append("key=");sb.append(Constants.API_KEY);String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();Log.e("Simon",">>>>"+packageSign);return packageSign;}/** 转换成xml*/private String toXml(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();sb.append("<xml>");for (int i = 0; i < params.size(); i++) {sb.append("<"+params.get(i).getName()+">");sb.append(params.get(i).getValue());sb.append("</"+params.get(i).getName()+">");}sb.append("</xml>");Log.e("Simon",">>>>"+sb.toString());return sb.toString();}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283

接下来就是有个支付结果的页面代码。是微信官方提供的一个类。你要在manifest注册这个类。这里需要注意的是,这个类必须放在wxapi包下,你自己新建一个包即可。

为了大家可以直接运行这个demo,我的微信加签都是在本地执行的,获取prepayid和加签都应该在服务端完成,还有最终的支付返回结果也是以服务端的为准。

*下面给出运行结果图*


大家下载demo然后把参数换了,弄下keystore,包名,签名。应该就可以用了。

Android 微信支付详解与Demo相关推荐

  1. android安装多个微信支付,android微信支付详解与坑

    要想在自己的APP中实现APP支付必须申请开通支付功能,这些按着文档来吧,我还是直接说Android中的问题吧. 一.签名 一定要在开放平台为自己的APP配置正确的包名和签名(签名:将APP打一个正式 ...

  2. Java=微信支付详解与日志记录详解

    一.二维码: (1)什么是二维码 二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示 ...

  3. Android 集成微信支付详解

    打包后才能起调支付 微信支付成功起调 微信skd下载:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1 签名APK下载:h ...

  4. 微信小程序API——微信支付详解(顺便讲一下我遇见的坑)

    学习微信小程序已经半个多月了,终于接触到小程序中一个很重要的功能--微信支付.接下来就给大家详细讲解一下微信支付功能的调用. 一想到微信支付,大家一定会去看微信小程序的API文档,没错,作为一个菜鸟我 ...

  5. Java对接微信支付详解

    一.介绍 微信支付对于我们日常来说,并不陌生,也许我们日常都在用.现在我就讲一下微信支付的流程是怎么实现的,都有哪些步骤,以及注意点. 支付流程图: 参数说明如图: 二.开发步骤 1.首先需要开通商户 ...

  6. 微信支付详解与取消支付回调

    第一步:绑定域名 先登录微信公众平台进入"公众号设置"的"功能设置"里填写"JS接口安全域名".如果你使用了支付类接口,请确保支付目录在该安 ...

  7. android+微信支付

    微信支付 目录 微信支付 1 一. 创建应用 2 二. 支付集成 5 1.body字段格式 8 三. 参考网址 12 四. Android Studio的两种模式及签名配置 12 一. 创建应用 1& ...

  8. 字节跳动小程序支付详解

    微信支付详解 1.为什么要写这篇文章 参考了字节跳动官方的文档之后发现写的太简单,完全一头雾水摸不清头脑,后来在百度了别人的实现方案,才得以总结出来. 2.背景 我司要开发一个头条小程序,需要支持支付 ...

  9. android微信支付代码,详解android微信支付实例代码

    这篇文章主要为大家详细介绍了http://www.php.cn/wiki/1502.html" target="_blank">android微信支付源码,具有一定 ...

最新文章

  1. img to image_tag
  2. 移动通信网络协议 — GTP 协议
  3. React Native的TextInput组件去掉下划线和使用背景图片
  4. 数据库以及后台开发之写在前面
  5. 最大公因数、最小公倍数、因式分解
  6. 原来流行也可以变成怀旧!
  7. GCC 链接时出现undefined reference to “...”时可能解决办法
  8. Mysql中Innodb大量插入数据时SQL语句的优化
  9. git cherry-pick 复制其他分支内容到当前分支
  10. registerModule: 动态注册vuex模块,对于自定义生成组件很有用
  11. java.lang.IllegalArgumentException at java.sql.Date.getHours
  12. Linux下获取时间差(毫秒级)
  13. java treetable_00035-layui+java 树形表格treeTable(异步请求)
  14. Zigbee协议栈中文说明
  15. 从GDPR和个保法看,为什么要做数据合规?
  16. 辐射光电流测试软件,资深工程师告诉你如何使用示波器测试EMI辐射干扰
  17. 手把手教你做一个APP应用(含源码)
  18. 错误: 找不到符号 符号: 类 DaggerActivityComponent错误解决
  19. node+express+mysql搭建一个系统
  20. 分类算法常用的评价指标

热门文章

  1. rust编程之道 pdf_深挖一篇嵌入式内核论文之后,我发现 Rust 正在悄悄改变世界...
  2. ES6的这些操作技巧,你会吗?
  3. 微信公众号监听返回按钮问题解决
  4. codevs 5963 [SDOI2017]树点染色
  5. Python之数据聚合与分组运算
  6. spark(一) build
  7. 【Android开发】布局管理器-线性布局
  8. 90%的用户都不知道手机内部功能
  9. 虚拟化,可实现国产化替代
  10. 如何训练大学生的工程实战能力