转载:http://blog.csdn.net/aicpzl/article/details/52993074

通过DownloadManager来下载APK到本地,下载完成后收到广播再安装APK,可用在软件更新等场合。

添加权限

[html] view plain copy
  1. <uses-permission android:name="android.permission.INTERNET"/>
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Activity源码

[java] view plain copy
  1. package com.example.administrator.downloadtest;
  2. import android.app.Activity;
  3. import android.app.DownloadManager;
  4. import android.content.BroadcastReceiver;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.IntentFilter;
  8. import android.net.Uri;
  9. import android.os.Bundle;
  10. import android.view.View;
  11. import android.webkit.MimeTypeMap;
  12. import android.widget.Button;
  13. public class MainActivity extends Activity {
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. Button btDownload = (Button) findViewById(R.id.bt_download);
  19. btDownload.setOnClickListener(new View.OnClickListener() {
  20. @Override
  21. public void onClick(View v) {
  22. downloadApk();
  23. }
  24. });
  25. /**注册下载完成广播**/
  26. registerReceiver(downloadCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
  27. }
  28. /**下载APK**/
  29. private void downloadApk() {
  30. String apkUrl = "http://192.168.1.1/downloadtest.apk";
  31. Uri uri = Uri.parse(apkUrl);
  32. DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
  33. DownloadManager.Request request = new DownloadManager.Request(uri);
  34. // 设置允许使用的网络类型,这里是移动网络和wifi都可以
  35. request.setAllowedNetworkTypes(request.NETWORK_MOBILE| request.NETWORK_WIFI);
  36. //设置是否允许漫游
  37. request.setAllowedOverRoaming(false);
  38. //设置文件类型
  39. MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
  40. String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(apkUrl));
  41. request.setMimeType(mimeString);
  42. //在通知栏中显示
  43. request.setNotificationVisibility(request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
  44. request.setTitle("download...");
  45. request.setVisibleInDownloadsUi(true);
  46. //sdcard目录下的download文件夹
  47. request.setDestinationInExternalPublicDir("/download", "downloadtest.apk");
  48. // 将下载请求放入队列
  49. downloadManager.enqueue(request);
  50. }
  51. private BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {
  52. @Override
  53. public void onReceive(Context context, Intent intent) {
  54. /**下载完成后安装APK**/
  55. installApk();
  56. }
  57. };
  58. private void installApk() {
  59. Intent i = new Intent(Intent.ACTION_VIEW);
  60. String filePath = "/sdcard/download/downloadtest.apk";
  61. i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
  62. startActivity(i);
  63. }
  64. }


[java] view plain copy
  1. package com.cardvalue.sys.activitys;
  2. import java.io.File;
  3. import java.io.UnsupportedEncodingException;
  4. import java.net.URLEncoder;
  5. import java.util.Date;
  6. import java.util.Map;
  7. import java.util.Set;
  8. import android.annotation.SuppressLint;
  9. import android.app.DownloadManager;
  10. import android.app.ProgressDialog;
  11. import android.content.BroadcastReceiver;
  12. import android.content.Context;
  13. import android.content.Intent;
  14. import android.content.IntentFilter;
  15. import android.database.Cursor;
  16. import android.net.ConnectivityManager;
  17. import android.net.NetworkInfo;
  18. import android.net.Uri;
  19. import android.os.Bundle;
  20. import android.text.TextUtils;
  21. import android.view.View;
  22. import android.view.View.OnClickListener;
  23. import android.view.Window;
  24. import android.view.WindowManager;
  25. import android.widget.Button;
  26. import android.widget.ImageView;
  27. import android.widget.RelativeLayout;
  28. import cn.jpush.android.api.InstrumentedActivity;
  29. import cn.jpush.android.api.JPushInterface;
  30. import cn.jpush.android.api.TagAliasCallback;
  31. import com.cardvlaue.sys.R;
  32. import com.cardvalue.sys.annotation.EControl;
  33. import com.cardvalue.sys.annotation.EventType;
  34. import com.cardvalue.sys.annotation.FCallHandler;
  35. import com.cardvalue.sys.annotation.FControl;
  36. import com.cardvalue.sys.common.CMessage;
  37. import com.cardvalue.sys.common.MD5Util;
  38. import com.cardvalue.sys.common.MessageBox;
  39. import com.cardvalue.sys.common.MyApplication;
  40. import com.cardvalue.sys.newnetwork.BusinessServices;
  41. import com.cardvalue.sys.newnetwork.Config;
  42. import com.cardvalue.sys.newnetwork.Convert;
  43. import com.cardvalue.sys.newnetwork.CustomHandler;
  44. import com.cardvalue.sys.newnetwork.UserServices;
  45. import com.cardvalue.sys.newnetwork.Utiltools;
  46. import com.cardvalue.sys.widget.WelcomeDialog;
  47. import com.cardvalue.sys.widget.WelcomeDialog.onAttendOrNotListener;
  48. import com.cardvalue.sys.widget.WelcomeDialog.onCancelListener;
  49. //import com.tencent.stat.StatService;
  50. /**
  51. * 欢迎页面
  52. */
  53. public class WelcomeActivity extends InstrumentedActivity {
  54. private Map<String, Object> active = null; // 活动页的相关信息
  55. private Map<String, Object> showIcon = null; // 首页显示的图标
  56. public CustomHandler handler;
  57. public ProgressDialog dialog;
  58. public UserServices userService = new UserServices();
  59. public BusinessServices businessService = new BusinessServices();
  60. @Override
  61. protected void onCreate(Bundle savedInstanceState) {
  62. super.onCreate(savedInstanceState);
  63. requestWindowFeature(Window.FEATURE_NO_TITLE);
  64. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  65. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  66. setContentView(R.layout.welcome);
  67. // StatService.trackCustomEvent(this, "onCreate", "");
  68. EControl control = new EControl(this);
  69. control.setOnClickLisenner(clickLinstenner); // 设置所有的点击事件
  70. control.InitControl(); // 开始初始化控件
  71. handler = new CustomHandler(this); // 初始化handler
  72. dialog = new ProgressDialog(this);
  73. JPushInterface.init(getApplicationContext());
  74. Utiltools.printE("Jpush data=========>"
  75. + JPushInterface.getRegistrationID(this));
  76. handler.sendMessage(handler.obtainMessage(MSG_SET_ALIAS, "android"));
  77. userService.setValue(this, handler, CMessage.NET_MSG_GETNEWVERSION);
  78. if (hasNetworkAvailable()) {
  79. userService.getVersionInformation();
  80. } else {
  81. MessageBox.ToastShow("没有可用网络连接,请检查你的网络!", WelcomeActivity.this);
  82. // 没有网络的时候直接到home页
  83. handler.sendEmptyMessageDelayed(NORMAL_MSG_HOME, 3000);
  84. }
  85. }
  86. /***********************************************************************************************************************************************
  87. * 定义控件,并指定控件对应的ID
  88. ***********************************************************************************************************************************************/
  89. @FControl(id = R.id.imageView1)
  90. public ImageView bg1; // 第一张背景图
  91. @FControl(id = R.id.imageView2, eventType = EventType.ON_CLICK)
  92. public ImageView bg2; // 第二张背景图
  93. @FControl(id = R.id.btn, eventType = EventType.ON_CLICK)
  94. public Button button; // 跳过按钮
  95. @FControl(id = R.id.ry_wecome)
  96. public RelativeLayout wLayout; // 第二张背景图及按钮的布局
  97. /*********************************************************************************************************************************************
  98. * 处理所有的onclick事件
  99. *********************************************************************************************************************************************/
  100. public OnClickListener clickLinstenner = new OnClickListener() {
  101. @Override
  102. public void onClick(View v) {
  103. switch (v.getId()) {
  104. case R.id.imageView2: // 按下了活动图片后触发
  105. String isForward = (String) active.get("forwardType"); // 判断是否跳转
  106. if (isForward.equals("1")) {
  107. handler.removeMessages(NORMAL_MSG_LOGIN);
  108. Intent intent = new Intent(WelcomeActivity.this,
  109. LoadWebPage.class);
  110. intent.putExtra("title", "活动规则");
  111. intent.putExtra("welcome", "welcome");
  112. intent.putExtra("url", (String) active.get("forwordUrl"));
  113. startActivity(intent);
  114. WelcomeActivity.this.finish();
  115. }
  116. break;
  117. case R.id.btn: // 按下了跳过按钮
  118. handler.removeMessages(NORMAL_MSG_LOGIN);
  119. startActivity(new Intent(WelcomeActivity.this, Home.class));
  120. WelcomeActivity.this.finish();
  121. break;
  122. }
  123. }
  124. };
  125. /**
  126. * 获取最新的服务器版本信息
  127. */
  128. @SuppressWarnings("unchecked")
  129. @FCallHandler(id = CMessage.NET_MSG_GETNEWVERSION)
  130. public void getNewVersion() {
  131. handler.tempMap = (Map<String, Object>) handler.resultMap
  132. .get("resultData");
  133. int clientCode = Utiltools.getAppVersionCode(this); // 客户端的版本code
  134. int serverCode = Integer.parseInt(handler.tempMap.get("versionCode")
  135. .toString()); // 服务端的版本code
  136. final String isForceUpdate = handler.tempMap.get("isForceUpdate")
  137. .toString(); // 是否强制更新 0不强制更新(可以选择) 1:必须更新
  138. active = (Map<String, Object>) handler.tempMap.get("welecomeSet");
  139. Utiltools.printE("handler.tempMap" + "=====" + handler.tempMap);
  140. Utiltools.printE("Convert.convertMap(active).size()" + "====="
  141. + Convert.convertMap(active).size());
  142. if (Convert.convertMap(active).size() != 0) {
  143. // http://www.cvbaoli.com/webak/resources/newm/images/welcome/welcome640-1136.png
  144. String imgUrl = Config.getWeixinIp() + "resources/image/welcome/"
  145. + (String) active.get("picName") + "640-1136."
  146. + (String) active.get("suffix");
  147. Utiltools.loadPic(this, imgUrl, bg2, R.drawable.welcome2,
  148. R.drawable.welcome2); // 加载网络图片
  149. Utiltools.printE("imgUrlimgUrl");
  150. } else {
  151. Utiltools.loadPic(this, "", bg2, R.drawable.welcome2,
  152. R.drawable.welcome2);
  153. Utiltools.printE("imgUrlimgUrl" + "===4444===");
  154. }
  155. // msg 中的内容根据是否强制更新的不同而进行改变
  156. String msg = isForceUpdate.equals("0") ? Utiltools
  157. .getString(R.string.updateSystem) : Utiltools
  158. .getString(R.string.needUpdateSystem);
  159. final WelcomeDialog mwelComeDialog = new WelcomeDialog(
  160. WelcomeActivity.this, msg);
  161. if (serverCode > clientCode) {// 服务器大于本地 就要更新
  162. onAttendOrNotListener welCome = new onAttendOrNotListener() {
  163. @SuppressLint("NewApi")
  164. @Override
  165. public void AttendOrNot() {
  166. MessageBox.show(dialog, "", "正在下载最新版本,请稍后...");
  167. String url = handler.tempMap.get("url").toString();
  168. DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
  169. DownloadManager.Request request = new DownloadManager.Request(
  170. Uri.parse(url));
  171. request.setDestinationInExternalPublicDir("/cardvalue",
  172. "cardvalue.apk");
  173. request.setVisibleInDownloadsUi(true);
  174. request.setTitle("卡得万利");
  175. downloadManager.enqueue(request);
  176. }
  177. };
  178. onCancelListener onCancel = new onCancelListener() {
  179. @Override
  180. public void Cancel() {
  181. if (isForceUpdate.equals("1")) {
  182. mwelComeDialog.cancel();
  183. WelcomeActivity.this.finish();
  184. } else {
  185. handler.sendEmptyMessage(NORMAL_MSG_START);
  186. mwelComeDialog.cancel();
  187. }
  188. }
  189. };
  190. mwelComeDialog.setOnAttendOrNotListener(welCome);
  191. mwelComeDialog.setCancelListener(onCancel);
  192. mwelComeDialog.show();
  193. } else {
  194. handler.sendEmptyMessage(NORMAL_MSG_START);
  195. }
  196. }
  197. /**
  198. * 开始正常的流程
  199. */
  200. @FCallHandler(id = NORMAL_MSG_START)
  201. public void startProcess() {
  202. Utiltools.printE("开始正常的流程=====" + Convert.convertMap(active).size());
  203. if (Convert.convertMap(active).size() == 0) {
  204. handler.sendEmptyMessageDelayed(NORMAL_MSG_LOGIN, 3000); // 5秒以后进入登录页
  205. return;
  206. }
  207. bg1.setVisibility(View.GONE); // 设置背景1层消失
  208. wLayout.setVisibility(View.VISIBLE); // 设置背景层显示
  209. bg2.setVisibility(View.VISIBLE); // 设置背景2层的图片显示
  210. button.setVisibility(View.VISIBLE); // 设置背景2层的按钮显示
  211. handler.sendEmptyMessageDelayed(NORMAL_MSG_LOGIN, 5000); // 5秒以后进入登录页
  212. }
  213. @FCallHandler(id = NORMAL_MSG_HOME)
  214. public void home() {
  215. startActivity(new Intent(WelcomeActivity.this, Home.class));
  216. WelcomeActivity.this.finish();
  217. }
  218. /**
  219. * 开始登陆操作
  220. */
  221. @FCallHandler(id = NORMAL_MSG_LOGIN)
  222. public void login() {
  223. Utiltools.printE("LOGIN====LOGIN");
  224. String username = MyApplication.getApplication().getLocalCache()
  225. .getString("username"); // 获取用户名
  226. String password = MyApplication.getApplication().getLocalCache()
  227. .getString("password"); // 获取密码
  228. if (username.equals("") || password.equals("")) {
  229. startActivity(new Intent(WelcomeActivity.this, Home.class));
  230. WelcomeActivity.this.finish();
  231. return;
  232. }
  233. String pushId = JPushInterface.getRegistrationID(this);
  234. long data = System.currentTimeMillis() / 1000;
  235. String pass1 = MD5Util.MD5(MD5Util.MD5(password) + "cvbaoli" + data)
  236. + "|" + data;
  237. try {
  238. userService.setValue(WelcomeActivity.this, handler,
  239. CMessage.NET_MSG_LOGIN);
  240. userService.login(username, URLEncoder.encode(pass1, "utf8"),
  241. "mj_"+pushId, null);
  242. } catch (UnsupportedEncodingException e) {
  243. e.printStackTrace();
  244. }
  245. }
  246. /**
  247. * 登陆成功后的操作
  248. */
  249. @FCallHandler(id = CMessage.NET_MSG_LOGIN)
  250. public void loginSuccess() {
  251. dialog.cancel();
  252. MyApplication.getApplication().setLogin(true);
  253. MyApplication.getApplication().getLocalCache()
  254. .putString("exirDate", String.valueOf(new Date().getTime()));
  255. startActivity(new Intent(WelcomeActivity.this, Home.class));
  256. WelcomeActivity.this.finish();
  257. }
  258. /**
  259. * 下载完成后广播接收类
  260. */
  261. class DownloadCompleteReceiver extends BroadcastReceiver {
  262. @SuppressLint("NewApi")
  263. @Override
  264. public void onReceive(Context context, Intent intent) {
  265. if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
  266. DownloadManager downloadManager = (DownloadManager) context
  267. .getSystemService(Context.DOWNLOAD_SERVICE);
  268. DownloadManager.Query query = new DownloadManager.Query();
  269. query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
  270. Cursor c = downloadManager.query(query);
  271. // 获取文件名并开始安装
  272. if (c.moveToFirst()) {
  273. String fileName = c.getString(c
  274. .getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
  275. fileName = fileName.replace("file://", "");
  276. File file = new File(fileName);
  277. Utiltools.print("weiweina", "file = " + fileName);
  278. Intent intent1 = new Intent(Intent.ACTION_VIEW);
  279. intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  280. intent1.setDataAndType(Uri.fromFile(file),
  281. "application/vnd.android.package-archive");
  282. startActivity(intent1);
  283. WelcomeActivity.this.finish();
  284. }
  285. }
  286. }
  287. }
  288. // 注册广播
  289. public DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
  290. @Override
  291. protected void onResume() {
  292. registerReceiver(receiver, new IntentFilter(
  293. DownloadManager.ACTION_DOWNLOAD_COMPLETE));
  294. super.onResume();
  295. }
  296. @Override
  297. protected void onDestroy() {
  298. if (receiver != null)
  299. unregisterReceiver(receiver);
  300. super.onDestroy();
  301. }
  302. /****************************************************************************************************************************************
  303. * 自定义消息
  304. ****************************************************************************************************************************************/
  305. private static final int NORMAL_MSG_START = 1; // 进入正常流程消息
  306. public static final int NORMAL_MSG_LOGIN = 2; // 开始进行登陆操作
  307. public static final int NORMAL_MSG_HOME = 3; // 延迟3秒到首页
  308. public static final int MSG_SET_ALIAS = 10001;
  309. public static final String MESSAGE_RECEIVED_ACTION = "com.cardvlaue.sys.MESSAGE_RECEIVED_ACTION";
  310. public static final String KEY_TITLE = "title";
  311. public static final String KEY_MESSAGE = "message";
  312. public static final String KEY_EXTRAS = "extras";
  313. private final TagAliasCallback mAliasCallback = new TagAliasCallback() {
  314. @Override
  315. public void gotResult(int code, String alias, Set<String> tags) {
  316. switch (code) {
  317. case 6002:
  318. if (isConnected(getApplicationContext())) {
  319. handler.sendMessageDelayed(
  320. handler.obtainMessage(MSG_SET_ALIAS, alias),
  321. 1000 * 60);
  322. }
  323. break;
  324. }
  325. }
  326. };
  327. public static boolean isConnected(Context context) {
  328. ConnectivityManager conn = (ConnectivityManager) context
  329. .getSystemService(Context.CONNECTIVITY_SERVICE);
  330. NetworkInfo info = conn.getActiveNetworkInfo();
  331. return (info != null && info.isConnected());
  332. }
  333. @FCallHandler(id = MSG_SET_ALIAS)
  334. public void setAlias() {
  335. Utiltools.print("极光调用了......................");
  336. JPushInterface.setAliasAndTags(getApplicationContext(),
  337. (String) handler.msg.obj, null, mAliasCallback);
  338. }
  339. /**
  340. * 判断网络是否连接
  341. */
  342. private boolean hasNetworkAvailable() {
  343. ConnectivityManager cm = (ConnectivityManager) this
  344. .getSystemService(Context.CONNECTIVITY_SERVICE);
  345. if (cm == null) {
  346. return false;
  347. } else {
  348. NetworkInfo[] info = cm.getAllNetworkInfo();
  349. if (info != null) {
  350. for (int i = 0; i < info.length; i++) {
  351. if (info[i].getState() == NetworkInfo.State.CONNECTED) {
  352. return true;
  353. }
  354. }
  355. }
  356. }
  357. return false;
  358. }
  359. }

Android 下载App的更多相关文章

  1. 分享我开发的网络电话Android手机APP正式版,图文详解及下载

    分享我开发的网络电话Android手机APP正式版,图文详解及下载 分享我开发的网络电话Android手机APP正式版 实时语音通讯,可广域网实时通讯,音质清晰流畅! 安装之后的运行效果: 第一次安装 ...

  2. 轻松搞定表白女朋友:Android版APP (零基础也可直接下载软件)

    在我们平时生活当中,经常会看到一些表白女朋友的html网页,但是Android端的表白软件可以说是基本没有,笔者在全网搜了一下,就没有一个可以用的.安卓端可以给人一种定制和精美的感觉,这是网页所做不到 ...

  3. 推荐下载App,如果本地安装则直接打开本地App(Android/IOS)

    推荐下载App,如果本地安装则直接打开本地App(Android/IOS) - 纵观现在每家移动网站,打开首页的时候,都有各种各样的形式来提示你下载自身的移动App(Android/IOS),这是做移 ...

  4. 通过扫码打开IOS的App Store下载APP(Android版暂时没找到解决方法)

    项目需求:扫码根据不同平台下载不同版本的APP.主要是ios和Android. 网上找了很多,前面判断平台的代码很容易找到,但是后面的就有些坑了.有的人的是根本跑不通.有的是代码补全. 下面是 微信扫 ...

  5. Cordova 打包 Android release app 过程详解

    Cordova 打包 Android release app 过程详解 时间 -- :: SegmentFault 原文 https://segmentfault.com/a/119000000517 ...

  6. Android 下载文件及写入SD卡

    Android 下载文件及写入SD卡,实例代码 <?xml version="1.0" encoding="utf-8"?> <LinearL ...

  7. 手机扫描二维码下载APP,根据操作系统不同自动下载

    Android和IOS手机扫描二维码下载APP,根据OS不同,自动处理相应下载操作.IOS自动跳转至AppStore应用下载页,Android自动下载应用的apk包. <script type= ...

  8. Android 下载模块分析(DownloadManager和DownloadProvider)

    Android下载模块主要有2个部分组成:DownloadManager和DownloadProvider:其中DownloadManager提供接口供调用,具体的实现是 DownloadProvid ...

  9. 微信扫码下载APP

    前段时间开发过程中,要实现一个扫描二维码下载APP的功能,但是苹果系统中,微信不可以直接跳转苹果商店,需要先下载应用宝,显然太麻烦... 这样我们可以做个中间页,用中间页面生成二维码链接,在中间页代码 ...

随机推荐

  1. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  2. 二、xadmin----简单使用

    1.中文设置: settings.py中直接配置: LANGUAGE_CODE = "zh-hans" TIME_ZONG = "Asia/Shanghai" ...

  3. long double

    long double 输入输出 scanf("%Lf",&a); printf("%.20Lf\n",a);

  4. IP核引发的关于定,浮点数的认识

    上面是一段关于CORDIC_IP测试文件,用于计算给定角度的sin值和cos值,关于数值表示规则在此不再重复,仅仅说明以下3点: 1  数采用原码,反码,补码,本身并没有正确与否之分(这一点很重要,我 ...

  5. Python删除list里面的重复元素的俩种方法

    1.使用set函数  In [116]: a=[1,2,3,2,1,3,4,5,6,5] In [117]: set(a) Out[117]: {1, 2, 3, 4, 5, 6} 2.使用字典函数 ...

  6. Python_阻塞IO、非阻塞IO、IO多路复用

    0.承上 进程: 计算机里最小的资源分配单位: 数据隔离, 利用多核,数据不安全. 线程: 计算机中最小的CPU调度单位: 数据共享,GIL锁,数据不安全. 协程: 线程的一部分,是有用户来调度的; ...

  7. asp.net mvc Areas 母版页动态获取数据进行渲染

    经常需要将一些通用的页面元素抽离出来制作成母版页,但是这里的元素一般都是些基本元素,即不需要 进行后台数据交换的基本数据,但是对于一些需要通过后台查询的数据,我们应该怎么传递给前台的母版页呢 这里描述 ...

  8. 通过arcmap发布缓存服务,无法选择自定义方案

    出现该问题是因为缓存目录有该缓存信息,清楚掉之后就可以选择自定义方案了

  9. LLVM的安装

    1. 官网下载 llvm 2. 官网下载cmake 3. configure 执行 llvm 发现报错 4. 解压缩 cmake 5.将cmake 下面的bin 目录放到环境变量里面去 6. 创建一个 ...

  10. for循环游标