当前位置:   article > 正文

android双卡时对apn的操作_android 添加apn数据到卡二

android 添加apn数据到卡二

apn(access point names),每个卡都会对应一系列的apn,如主卡为联通卡,对应的apn有3gwap/3gnet/uninet/nuiwap/3gwap等。每个卡默认选择一个apn,用户可更改。

1. 获取主卡或副卡当前使用的apn,对应的uri地址:"content://telephony/carriers/preferapn"。

  1. APN getAPN(int subId)
  2. Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
  3. uri = Uri.withAppendedPath(PREFERAPN_URI, "/subId/" + subId);

slotId和subId:可以根据卡槽的slotId得到subId:

    int subId = MtkSubscriptionManager.getSubIdUsingPhoneId(slotId);

2. 获取主卡或副卡所有的apn列表,对应的uri地址:"content://telephony/carriers"。

  1. List<APN> getApnList(int subId)//某个卡槽对应的APN列表
  2. uri = Uri.parse("content://telephony/carriers");
  3. String mccmnc = mTelephonyManager.getSimOperator(subId);//where条件根据mccmnc得到
  4. //主副卡,可根据current来区分,"current = 1",表示在使用的sim卡,即主卡。"current = 0",为副卡。

3. 针对某个卡增加apn

  1.     boolean addApn(APN newApn)
  2. uri = Uri.parse("content://telephony/carriers");

4. 更新或删除某个卡的某一apn
    boolean update(APN apn)

  1.     boolean update(APN apn)
  2. boolean removeAPN(APN apn)
  3. int pos = Integer.parseInt(apn.apnkey);
  4. mUri = Uri.parse("content://telephony/carriers");
  5. uri = ContentUris.withAppendedId(mUri, pos);

5. 恢复apn到默认状态  

  1. boolean restoreDefaultApn(int subId) //把某个卡槽对应的APN恢复到默认值
  2. Uri DEFAULTAPN_URI = Uri.parse("content://telephony/carriers/restore");
  3. uri = Uri.withAppendedPath(DEFAULTAPN_URI, "/subId/" + subId);

    若是插入双卡,只要一个卡执行该功能,两个卡的apn都会恢复到初始值。

6. 代码如下

  1. public class MyAPNManager {
  2. private static final String TAG = "MyAPNManager";
  3. private static final boolean DEBUG = true;
  4. public static final String RESTORE_CARRIERS_URI = "content://telephony/carriers/restore";
  5. public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
  6. private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI);
  7. private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI);
  8. /**
  9. * Standard projection for the interesting columns of a normal note.
  10. */
  11. private static final String[] PROJECTION = new String[] {
  12. Telephony.Carriers._ID, // 0
  13. Telephony.Carriers.NAME,
  14. Telephony.Carriers.APN,
  15. Telephony.Carriers.PROXY,
  16. Telephony.Carriers.PORT,
  17. Telephony.Carriers.USER, // 5
  18. Telephony.Carriers.PASSWORD,
  19. Telephony.Carriers.SERVER,
  20. Telephony.Carriers.MMSC,
  21. Telephony.Carriers.MMSPROXY,
  22. Telephony.Carriers.MMSPORT, //10
  23. Telephony.Carriers.MCC,
  24. Telephony.Carriers.MNC,
  25. Telephony.Carriers.AUTH_TYPE,
  26. Telephony.Carriers.TYPE,//type
  27. Telephony.Carriers.PROTOCOL,//15
  28. Telephony.Carriers.ROAMING_PROTOCOL,
  29. Telephony.Carriers.CARRIER_ENABLED,
  30. Telephony.Carriers.BEARER,
  31. Telephony.Carriers.MVNO_TYPE,
  32. Telephony.Carriers.MVNO_MATCH_DATA,//20
  33. Telephony.Carriers.USER_VISIBLE
  34. //Telephony.Carriers.NUMERIC,
  35. //Telephony.Carriers.CURRENT
  36. };
  37. protected TelephonyManager mTelephonyManager;
  38. private int mSlotId;
  39. protected Uri mUri;
  40. private Context mContext;
  41. private SubscriptionManager mSubscrMgr;
  42. //private SubscriptionInfo mSubscriptionInfo;
  43. private int mSubId, mSubId1;
  44. private ContentResolver mResolver;
  45. private SubscriptionInfo subscriptionInfo;
  46.     private int mSlotCnt = 0;//the count of Slot
  47. public MyAPNManager(Context context) {
  48. debug("enter MyAPNManager()");
  49. mContext = context;
  50. mSlotId = 0;//single sim card
  51. mTelephonyManager = (TelephonyManager) context
  52. .getSystemService(Context.TELEPHONY_SERVICE);
  53. mSubscrMgr = SubscriptionManager.from(mContext);
  54. mResolver = mContext.getContentResolver();
  55. mSlotCnt = mTelephonyManager.getSimCount();//get the count of Slot
  56. debug("mSlotCnt = " + mSlotCnt);
  57. //mSubscriptionInfo = SubscriptionManager.from(activity).getActiveSubscriptionInfo(subId);
  58. //mSubscriptionInfo = mSubscrMgr.getActiveSubscriptionInfoForSimSlotIndex(soltId);
  59. mSubId = getSubIdBySlotId(mSlotId);
  60. mSubId1 = getSubIdBySlotId(1);
  61. int subId = MtkSubscriptionManager.getSubIdUsingPhoneId(0);
  62. int subId1 = MtkSubscriptionManager.getSubIdUsingPhoneId(1);
  63. debug("mSubId = " + mSubId + ", mSubId1 = " + mSubId1 + ", subId = " + subId + ", subId1 = " + subId1);
  64. mUri = Telephony.Carriers.CONTENT_URI;
  65. }
  66. private int getSubIdBySlotId(int slotId){
  67. debug("enter getSubIdBySlotId()");
  68. int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
  69. subscriptionInfo = mSubscrMgr.getActiveSubscriptionInfoForSimSlotIndex(slotId);
  70. debug("slotId=" + slotId + ", subscriptionInfo = " + subscriptionInfo);
  71. if(null != subscriptionInfo){
  72. subId = subscriptionInfo.getSubscriptionId();
  73. }
  74. debug("subId = " + subId);
  75. return subId;
  76. }
  77. /* 2.1 get current apn begin */
  78. public APN getAPN(int slotId){
  79. int subId = MtkSubscriptionManager.getSubIdUsingPhoneId(slotId);
  80. debug("enter getAPN() subId = " + subId);
  81. APN myApn = null;
  82. Cursor cursor = null;
  83. try{
  84. cursor = mResolver.query(getPreferApnUri(subId), PROJECTION,
  85. null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
  86. debug("cursor = " + cursor + " : " + cursor.getCount());
  87. if (cursor.getCount() > 0) {//if (cur != null && cur.moveToFirst())
  88. cursor.moveToFirst();
  89. myApn = new APN(cursor.getString(0), cursor.getString(1), cursor.getString(2),
  90. cursor.getString(3), cursor.getString(4), cursor.getString(5),
  91. cursor.getString(6), cursor.getString(7), cursor.getString(8),
  92. cursor.getString(9), cursor.getString(10), cursor.getString(11),
  93. cursor.getString(12), cursor.getInt(13), cursor.getString(14),
  94. cursor.getString(15), cursor.getString(16), cursor.getInt(17),
  95. cursor.getString(18), cursor.getString(19), cursor.getString(20),
  96. cursor.getInt(21));
  97. }
  98. debug("myApn = " + myApn);
  99. } catch(Exception e){
  100. e.printStackTrace();
  101. } finally{
  102. if(cursor!=null)
  103. cursor.close();
  104. }
  105. return myApn;
  106. }
  107. private Uri getPreferApnUri(int subId) {
  108. Uri preferredUri = Uri.withAppendedPath(PREFERAPN_URI, "/subId/" + subId);
  109. debug("getPreferredApnUri: " + preferredUri);
  110. return preferredUri;
  111. }
  112. /* 2.1 get current apn end */
  113. /* 2.2 get list of apn begin */
  114. private String getWhere(int subId){
  115. debug("enter getWhere()");
  116. String mccmnc = mTelephonyManager.getSimOperator(subId);
  117. debug("mccmnc = " + mccmnc);
  118. String where = "numeric=\"" + mccmnc + "\"";
  119. where += " AND NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND user_visible!=0";
  120. //debug("1 where: " + where);
  121. /// M: for VoLTE, do not show ims apn for non-VoLTE project
  122. if (!FeatureOption.MTK_VOLTE_SUPPORT) {
  123. where += " AND NOT (type='ims' OR type='ia,ims')";
  124. //debug("2 where: " + where);
  125. }
  126. debug("where: " + where);
  127. return where;
  128. }
  129. private boolean shouldSkipApn(String type) {
  130. boolean isSkipApn = "cmmail".equals(type);
  131. debug("isSkipApn = " + isSkipApn);
  132. return isSkipApn;
  133. //return "cmmail".equals(type);
  134. }
  135. public List<APN> getApnList(int slotId){
  136. int subId = MtkSubscriptionManager.getSubIdUsingPhoneId(slotId);
  137. debug("enter getApnList() subId = " + subId + ", mUri = " + mUri);
  138. List<APN> apnList = new ArrayList<APN>();
  139. APN apnInfo = null;
  140. //String projection[] = {"_id", "name", "apn", "type", "current", "mcc", "mnc", "carrier_enabled", "mvno_type", "mvno_match_data"};
  141. String where = getWhere(subId);
  142. Cursor cursor = null;
  143. try{
  144. cursor = mResolver.query(
  145. mUri,//Telephony.Carriers.CONTENT_URI,
  146. PROJECTION,
  147. where.toString(),
  148. null,
  149. Telephony.Carriers.DEFAULT_SORT_ORDER);
  150. debug("cursor = " + cursor + " : " + cursor.getCount());
  151. if(null != cursor){
  152. int pid = android.os.Process.myPid();
  153. String procName = null;
  154. ActivityManager mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
  155. for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {
  156. if (appProcess.pid == pid) {
  157. procName = appProcess.processName;
  158. }
  159. }
  160. debug("procName = " + procName + ", pid = " + pid);
  161. while(cursor.moveToNext()){
  162. String type = cursor.getString(14);//"type"
  163. String mvnoType = cursor.getString(19);
  164. String mvnoMatchData = cursor.getString(20);
  165. if(shouldSkipApn(type)) {
  166. //debug("will move next");
  167. cursor.moveToNext();
  168. continue;
  169. }
  170. if (!TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)) {
  171. //mvnoList -- 虚拟运营商 --只要是虚拟运营商都不会显示?
  172. } else {
  173. //mnoList -- MVNO(Mobile Virtaul Network Operator)虚拟网络运营商,没有自己的实体网络,通过租用MNO(Mobile Network Operator)的网络来提供网络服务。
  174. apnInfo = new APN(cursor.getString(0), cursor.getString(1), cursor.getString(2),
  175. cursor.getString(3), cursor.getString(4), cursor.getString(5),
  176. cursor.getString(6), cursor.getString(7), cursor.getString(8),
  177. cursor.getString(9), cursor.getString(10), cursor.getString(11),
  178. cursor.getString(12), cursor.getInt(13), cursor.getString(14),
  179. cursor.getString(15), cursor.getString(16), cursor.getInt(17),
  180. cursor.getString(18), cursor.getString(19), cursor.getString(20),
  181. cursor.getInt(21));
  182. //debug("apnInfo = " + apnInfo);
  183. apnList.add(apnInfo);
  184. }
  185. }
  186. }
  187. debug("apnList = " + apnList);
  188. } catch(Exception e){
  189. e.printStackTrace();
  190. } finally{
  191. if(cursor!=null)
  192. cursor.close();
  193. }
  194. return apnList;
  195. }
  196. /* 2.2 get list of apn end */
  197. /* 2.3 update apn begin */
  198. public boolean updateApn(APN newApn, boolean force) {//'mSlotId' is not used
  199. debug("force = " + force + ", newApn = " + newApn);
  200. return update(mContext, force, /*mSlotId,*/ newApn.getKey(),
  201. newApn.getName(), newApn.getApn(), newApn.getProxy(),
  202. newApn.getPort(), newApn.getUser(), newApn.getPassword(),
  203. newApn.getServer(), newApn.getMmsc(), newApn.getMmsproxy(),
  204. newApn.getMmsport(), newApn.getMcc(), newApn.getMnc(),
  205. newApn.getAuthTypeVal(), newApn.getApnType(), newApn.getApnProtocol(),
  206. newApn.getRoamingProtocol(), newApn.getCarrierEnabled(),
  207. newApn.getBearerVal());
  208. }
  209. public boolean update(Context context, boolean force, /*int slotId,*/
  210. String apnkey, String name, String apn, String proxy,
  211. String port, String user, String password, String server,
  212. String mmsc, String mmsproxy, String mmsport, String mcc,
  213. String mnc, int authTypeVal, String strType, String protocol,
  214. String roamingProtocol, int carrierEnabled, String bearerVal) {
  215. int pos = Integer.parseInt(apnkey);
  216. Uri uri = ContentUris.withAppendedId(mUri, pos);
  217. debug("apnkey = " + apnkey + ", pos = " + pos + ", mUri = " + mUri + ", uri = " + uri);
  218. if (!force
  219. && (name.length() < 1 || apn.length() < 1 || mcc.length() != 3 || (mnc
  220. .length() & 0xFFFE) != 2)) {
  221. return false;
  222. }
  223. ContentValues values = new ContentValues();
  224. values.put(Telephony.Carriers.NAME, name);
  225. values.put(Telephony.Carriers.APN, apn);
  226. values.put(Telephony.Carriers.PROXY, checkNotSet(proxy));
  227. values.put(Telephony.Carriers.PORT, checkNotSet(port));
  228. values.put(Telephony.Carriers.USER, checkNotSet(user));
  229. values.put(Telephony.Carriers.PASSWORD, checkNotSet(password));
  230. values.put(Telephony.Carriers.SERVER, checkNotSet(server));
  231. values.put(Telephony.Carriers.MMSC, checkNotSet(mmsc));
  232. values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mmsproxy));
  233. values.put(Telephony.Carriers.MMSPORT, checkNotSet(mmsport));
  234. values.put(Telephony.Carriers.AUTH_TYPE, authTypeVal);
  235. values.put(Telephony.Carriers.TYPE, checkNotSet(strType));
  236. values.put(Telephony.Carriers.PROTOCOL, checkNotSet(protocol));
  237. values.put(Telephony.Carriers.ROAMING_PROTOCOL, checkNotSet(roamingProtocol));
  238. values.put(Telephony.Carriers.CARRIER_ENABLED, carrierEnabled);
  239. values.put(Telephony.Carriers.MCC, mcc);
  240. values.put(Telephony.Carriers.MNC, mnc);
  241. values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
  242. debug("values = " + values);
  243. String numeric = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
  244. debug("numeric = " + numeric);
  245. String curMnc = null;
  246. String curMcc = null;
  247. // MCC is first 3 chars and then in 2 - 3 chars of MNC
  248. if (numeric != null && numeric.length() > 4) {
  249. // Country code
  250. curMcc = numeric.substring(0, 3);
  251. // Network code
  252. curMnc = numeric.substring(3);
  253. debug("curMcc = " + curMcc + ", curMnc = " + curMnc);
  254. }
  255. if (curMnc != null && curMcc != null) {
  256. if (curMnc.equals(mnc) && curMcc.equals(mcc)) {
  257. values.put(Telephony.Carriers.CURRENT, 1);
  258. }
  259. }
  260. if (bearerVal != null) {
  261. values.put(Telephony.Carriers.BEARER, Integer.parseInt(bearerVal));
  262. }
  263. values.put(MtkTelephony.Carriers.SOURCE_TYPE, 1);
  264. int count = 0;
  265. if (uri != null) {
  266. count = context.getContentResolver()
  267. .update(uri, values, null, null);
  268. }
  269. return count > 0 ? true : false;
  270. }
  271. private String checkNotSet(String value) {
  272. return value == null ? "" : value;
  273. }
  274. /* 2.3 update apn end */
  275. /* 2.4 remove apn begin */
  276. /**
  277. * Remove a APN for specific key.
  278. * @param apnKey key of apn
  279. * @return true if the apn was deleted
  280. */
  281. public boolean removeAPN(String apnKey) {
  282. debug("enter removeAPN()");
  283. int pos = Integer.parseInt(apnKey);
  284. Uri uri = ContentUris.withAppendedId(mUri, pos);
  285. debug("apnKey-->" + apnKey +", uri--->" + uri);
  286. int count = 0;
  287. if (uri != null) {
  288. count = mContext.getContentResolver().delete(uri, null, null);
  289. }
  290. return count > 0 ? true : false;
  291. }
  292. /* 2.4 remove apn end */
  293. /* 2.5 restore to defualt begin */
  294. public boolean restoreDefaultApn() {
  295. debug("enter restoreDefaultApn()");
  296. SubscriptionInfo subInfo = null;
  297. for (int i = 0; i < mSlotCnt; ++i) {
  298. subInfo = mSubscrMgr.getActiveSubscriptionInfoForSimSlotIndex(i);
  299. debug(i + " : " + subInfo);
  300. if (subInfo != null) {
  301. int subId = subInfo.getSubscriptionId();
  302. mResolver.delete(getDefaultApnUri(subId), null, null);
  303. debug("will return true");
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. private Uri getDefaultApnUri(int subId) {
  310. Uri defaultUri = Uri.withAppendedPath(DEFAULTAPN_URI, "/subId/" + subId);
  311. debug("default apn uri : " + defaultUri);
  312. return defaultUri;
  313. }
  314. /* 2.5 restore to defualt end */
  315. /* 2.7 add apn */
  316. /**
  317. * Check the key fields' validity and save if valid.
  318. * @param force save even if the fields are not valid, if the app is
  319. * being suspended
  320. * @return true if there's no error
  321. */
  322. public boolean addApn(APN newApn, boolean force) {
  323. debug("validateAndSave... force = " + force);
  324. String name = checkNotSet(newApn.getName());
  325. String apn = checkNotSet(newApn.getApn());
  326. String mcc = checkNotSet(newApn.getMcc());
  327. String mnc = checkNotSet(newApn.getMnc());
  328. String apnType = newApn.getApnType();
  329. debug("name = " + name + ", apn = " + apn);
  330. debug("mcc = " + mcc + ", mnc = " + mnc);
  331. debug("apnType = " + apnType);
  332. Uri uri = mUri;
  333. uri = mContext.getContentResolver().insert(uri, new ContentValues());
  334. debug("uri = " + uri);
  335. if ( !force
  336. && ( (name.length() < 1)
  337. || (mcc.length() != 3)
  338. || ((mnc.length() & 0xFFFE) != 2)
  339. || ( (apnType == null || !apnType.contains("ia"))
  340. && apn.length() < 1))){
  341. debug("force = false, and teturn");
  342. return false;
  343. }
  344. // If it's a new APN and a name or apn haven't been entered, then erase the entry
  345. if (force && name.length() < 1 && apn.length() < 1 && uri != null) {
  346. mContext.getContentResolver().delete(uri, null, null);
  347. uri = null;
  348. debug("force = true, and teturn");
  349. return false;
  350. }
  351. ContentValues values = new ContentValues();
  352. values.put(Telephony.Carriers.NAME, name);
  353. values.put(Telephony.Carriers.APN, apn);
  354. values.put(Telephony.Carriers.PROXY, checkNotSet(newApn.getProxy()));
  355. values.put(Telephony.Carriers.PORT, checkNotSet(newApn.getPort()));
  356. values.put(Telephony.Carriers.USER, checkNotSet(newApn.getUser()));
  357. values.put(Telephony.Carriers.PASSWORD, checkNotSet(newApn.getPassword()));
  358. values.put(Telephony.Carriers.SERVER, checkNotSet(newApn.getServer()));
  359. values.put(Telephony.Carriers.MMSC, checkNotSet(newApn.getMmsc()));
  360. values.put(Telephony.Carriers.MMSPROXY, checkNotSet(newApn.getMmsproxy()));
  361. values.put(Telephony.Carriers.MMSPORT, checkNotSet(newApn.getMmsport()));
  362. values.put(Telephony.Carriers.AUTH_TYPE, newApn.getAuthTypeVal());
  363. values.put(Telephony.Carriers.TYPE, apnType);
  364. values.put(Telephony.Carriers.PROTOCOL, checkNotSet(newApn.getApnProtocol()));
  365. values.put(Telephony.Carriers.ROAMING_PROTOCOL, checkNotSet(newApn.getRoamingProtocol() ));
  366. //values.put(Telephony.Carriers.CARRIER_ENABLED, getCarrierEnabled());
  367. values.put(Telephony.Carriers.MCC, mcc);
  368. values.put(Telephony.Carriers.MNC, mnc);
  369. values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
  370. debug("values = " + values);
  371. String numeric = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
  372. debug("numeric = " + numeric);
  373. String curMnc = null;
  374. String curMcc = null;
  375. // MCC is first 3 chars and then in 2 - 3 chars of MNC
  376. if (numeric != null && numeric.length() > 4) {
  377. // Country code
  378. curMcc = numeric.substring(0, 3);
  379. // Network code
  380. curMnc = numeric.substring(3);
  381. debug("curMcc = " + curMcc + ", curMnc = " + curMnc);
  382. }
  383. if (curMnc != null && curMcc != null) {
  384. if (curMnc.equals(mnc) && curMcc.equals(mcc)) {
  385. values.put(Telephony.Carriers.CURRENT, 1);
  386. }
  387. }
  388. String bearerVal = newApn.getBearerVal();
  389. if (bearerVal != null) {
  390. values.put(Telephony.Carriers.BEARER, Integer.parseInt(bearerVal));
  391. }
  392. values.put(MtkTelephony.Carriers.SOURCE_TYPE, 1);
  393. debug("values = " + values);
  394. int count = 0;
  395. if (uri != null) {
  396. count = mContext.getContentResolver()
  397. .update(uri, values, null, null);
  398. debug("111 count = " + count);
  399. }
  400. debug("222 count = " + count);
  401. return count > 0 ? true : false;
  402. }
  403. /* 2.8 get mcc and mnc */
  404. public String getMccMnc(int slotId){
  405. int subId = MtkSubscriptionManager.getSubIdUsingPhoneId(slotId);
  406. debug("enter getMccMnc() slotId = " + slotId + ", subId = " + subId);
  407. String mccmnc = mTelephonyManager.getSimOperator(subId);
  408. debug("mccmnc = " + mccmnc);
  409. /*String mccmnc = null;
  410. Cursor cursor = null;
  411. try{
  412. cursor = mResolver.query(getPreferApnUri(subId), PROJECTION,
  413. null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
  414. debug("cursor = " + cursor + " : " + cursor.getCount());
  415. if (cursor.getCount() > 0) {//if (cur != null && cur.moveToFirst())
  416. cursor.moveToFirst();
  417. mccmnc = cursor.getString(11) + cursor.getString(12);
  418. }
  419. debug("mccmnc = " + mccmnc);
  420. } catch(Exception e){
  421. e.printStackTrace();
  422. } finally{
  423. if(cursor!=null)
  424. cursor.close();
  425. }*/
  426. return mccmnc;
  427. }
  428. private void debug(String str) {
  429. if (DEBUG) {
  430. Log.d(TAG, str);
  431. }
  432. }
  433. }

参考:
    https://blog.csdn.net/gf771115/article/details/8212671
    https://blog.csdn.net/lll1204019292/article/details/52260817
    https://www.cnblogs.com/sishuiliuyun/p/3754516.html
    https://yq.aliyun.com/ziliao/116416
    https://blog.csdn.net/treasure3334/article/details/7816361
    https://blog.csdn.net/zidan_2011/article/details/7704865

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/988239
推荐阅读
相关标签
  

闽ICP备14008679号