草庐IT

java - Youtube 数据 API : Get access to media stream and play (JAVA)

coder 2023-08-29 原文

我想访问 YouTube 视频并使用我自己的媒体播放器播放。我可以使用 youtube 数据 API 获取视频属性(标题、url 等)。我可以访问视频流并使用我自己的媒体播放器(如 Android 媒体播放器)播放它吗? 我正在 JAVA 中尝试所有这些。

提前致谢..:)

最佳答案

/**
 * This work is licensed under a Creative Commons Attribution 3.0 Unported
 * License (http://creativecommons.org/licenses/by/3.0/). This work is placed
 * into the public domain by the author.
 */
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

/**
 * Locally download a YouTube.com video.
 */
public class JavaYoutubeDownloader extends Formatter {

 private static final String scheme = "http";
 private static final String host = "www.youtube.com";
 private static final String YOUTUBE_WATCH_URL_PREFIX = scheme + "://" + host + "/watch?v=";
 private static final String ERROR_MISSING_VIDEO_ID = "Missing video id. Extract from " + YOUTUBE_WATCH_URL_PREFIX + "VIDEO_ID";
 private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
 private static final String DEFAULT_ENCODING = "UTF-8";
 private static final String newline = System.getProperty("line.separator");
 private static final Logger log = Logger.getLogger(JavaYoutubeDownloader.class.getCanonicalName());
 private static final Logger rootlog = Logger.getLogger("");
 private static final Pattern commaPattern = Pattern.compile(",");
 private static final Pattern pipePattern = Pattern.compile("\\|");
 private static final char[] ILLEGAL_FILENAME_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };
 private static final int BUFFER_SIZE = 2048;
 private static final DecimalFormat commaFormatNoPrecision = new DecimalFormat("###,###");
 private static final double ONE_HUNDRED = 100;
 private static final double KB = 1024;

 private void usage(String error) {
  if (error != null) {
   System.err.println("Error: " + error);
  }
  System.err.println("usage: JavaYoutubeDownload VIDEO_ID");
  System.err.println();
  System.err.println("Options:");
  System.err.println("\t[-dir DESTINATION_DIR] - Specify output directory.");
  System.err.println("\t[-format FORMAT] - Format number" + newline + "\t\tSee http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs");
  System.err.println("\t[-ua USER_AGENT] - Emulate a browser user agent.");
  System.err.println("\t[-enc ENCODING] - Default character encoding.");
  System.err.println("\t[-verbose] - Verbose logging for downloader component.");
  System.err.println("\t[-verboseall] - Verbose logging for all components (e.g. HttpClient).");
  System.exit(-1);
 }

 public static void main(String[] args) {
  try {
   new JavaYoutubeDownloader().run(args);
  } catch (Throwable t) {
   t.printStackTrace();
  }
 }

 private void run(String[] args) throws Throwable {
  setupLogging(Level.WARNING, Level.WARNING);

  String videoId = null;
  String outdir = ".";
  int format = 18;
  String encoding = DEFAULT_ENCODING;
  String userAgent = DEFAULT_USER_AGENT;

  for (int i = 0; i < args.length; i++) {
   String arg = args[i];

   // Options start with either -, --
   // Do not accept Windows-style args that start with / because of abs
   // paths on linux for file names.
   if (arg.charAt(0) == '-') {

    // For easier processing, convert any double dashes to
    // single dashes
    if (arg.length() > 1 && arg.charAt(1) == '-') {
     arg = arg.substring(1);
    }

    String larg = arg.toLowerCase();

    // Process the option
    if (larg.equals("-help") || larg.equals("-?") || larg.equals("-usage") || larg.equals("-h")) {
     usage(null);
    } else if (larg.equals("-verbose")) {
     setupLogging(Level.ALL, Level.WARNING);
    } else if (larg.equals("-verboseall")) {
     setupLogging(Level.ALL, Level.ALL);
    } else if (larg.equals("-dir")) {
     outdir = args[++i];
    } else if (larg.equals("-format")) {
     format = Integer.parseInt(args[++i]);
    } else if (larg.equals("-ua")) {
     userAgent = args[++i];
    } else if (larg.equals("-enc")) {
     encoding = args[++i];
    } else {
     usage("Unknown command line option " + args[i]);
    }
   } else {
    // Non-option (i.e. does not start with -, --

    videoId = arg;

    // Break if only the first non-option should be used.
    break;
   }
  }

  if (videoId == null) {
   usage(ERROR_MISSING_VIDEO_ID);
  }

  log.fine("Starting");

  if (videoId.startsWith(YOUTUBE_WATCH_URL_PREFIX)) {
   videoId = videoId.substring(YOUTUBE_WATCH_URL_PREFIX.length());
  }
  int a = videoId.indexOf('&');
  if (a != -1) {
   videoId = videoId.substring(0, a);
  }

  File outputDir = new File(outdir);
  String extension = getExtension(format);

  play(videoId, format, encoding, userAgent, outputDir, extension);

  log.fine("Finished");
 }

 private static String getExtension(int format) {
  switch (format) {
  case 18:
   return "mp4";
  default:
   throw new Error("Unsupported format " + format);
  }
 }

 private static void play(String videoId, int format, String encoding, String userAgent, File outputdir, String extension) throws Throwable {
  log.fine("Retrieving " + videoId);
  List<NameValuePair> qparams = new ArrayList<NameValuePair>();
  qparams.add(new BasicNameValuePair("video_id", videoId));
  qparams.add(new BasicNameValuePair("fmt", "" + format));
  URI uri = getUri("get_video_info", qparams);

  CookieStore cookieStore = new BasicCookieStore();
  HttpContext localContext = new BasicHttpContext();
  localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

  HttpClient httpclient = new DefaultHttpClient();
  HttpGet httpget = new HttpGet(uri);
  if (userAgent != null && userAgent.length() > 0) {
   httpget.setHeader("User-Agent", userAgent);
  }

  log.finer("Executing " + uri);
  HttpResponse response = httpclient.execute(httpget, localContext);
  HttpEntity entity = response.getEntity();
  if (entity != null && response.getStatusLine().getStatusCode() == 200) {
   InputStream instream = entity.getContent();
   String videoInfo = getStringFromInputStream(encoding, instream);
   if (videoInfo != null && videoInfo.length() > 0) {
    List<NameValuePair> infoMap = new ArrayList<NameValuePair>();
    URLEncodedUtils.parse(infoMap, new Scanner(videoInfo), encoding);
    String downloadUrl = null;
    String filename = videoId;

    for (NameValuePair pair : infoMap) {
     String key = pair.getName();
     String val = pair.getValue();
     log.finest(key + "=" + val);
     if (key.equals("title")) {
      filename = val;
     } else if (key.equals("fmt_url_map")) {
      String[] formats = commaPattern.split(val);
      boolean found = false;
      for (String fmt : formats) {
       String[] fmtPieces = pipePattern.split(fmt);
       if (fmtPieces.length == 2) {
        int pieceFormat = Integer.parseInt(fmtPieces[0]);
        log.fine("Available format=" + pieceFormat);
        if (pieceFormat == format) {
         // found what we want
         downloadUrl = fmtPieces[1];
         found = true;
         break;
        }
       }
      }
      if (!found) {
       log.warning("Could not find video matching specified format, however some formats of the video do exist (use -verbose).");
      }
     }
    }

    filename = cleanFilename(filename);
    if (filename.length() == 0) {
     filename = videoId;
    } else {
     filename += "_" + videoId;
    }
    filename += "." + extension;
    File outputfile = new File(outputdir, filename);

    if (downloadUrl != null) {
     downloadWithHttpClient(userAgent, downloadUrl, outputfile);
    } else {
     log.severe("Could not find video");
    }
   } else {
    log.severe("Did not receive content from youtube");
   }
  } else {
   log.severe("Could not contact youtube: " + response.getStatusLine());
  }
 }

 private static void downloadWithHttpClient(String userAgent, String downloadUrl, File outputfile) throws Throwable {
  HttpGet httpget2 = new HttpGet(downloadUrl);
  if (userAgent != null && userAgent.length() > 0) {
   httpget2.setHeader("User-Agent", userAgent);
  }

  log.finer("Executing " + httpget2.getURI());
  HttpClient httpclient2 = new DefaultHttpClient();
  HttpResponse response2 = httpclient2.execute(httpget2);
  HttpEntity entity2 = response2.getEntity();
  if (entity2 != null && response2.getStatusLine().getStatusCode() == 200) {
   double length = entity2.getContentLength();
   if (length <= 0) {
    // Unexpected, but do not divide by zero
    length = 1;
   }
   InputStream instream2 = entity2.getContent();
   System.out.println("Writing " + commaFormatNoPrecision.format(length) + " bytes to " + outputfile);
   if (outputfile.exists()) {
    outputfile.delete();
   }
   FileOutputStream outstream = new FileOutputStream(outputfile);
   try {
    byte[] buffer = new byte[BUFFER_SIZE];
    double total = 0;
    int count = -1;
    int progress = 10;
    long start = System.currentTimeMillis();
    while ((count = instream2.read(buffer)) != -1) {
     total += count;
     int p = (int) ((total / length) * ONE_HUNDRED);
     if (p >= progress) {
      long now = System.currentTimeMillis();
      double s = (now - start) / 1000;
      int kbpers = (int) ((total / KB) / s);
      System.out.println(progress + "% (" + kbpers + "KB/s)");
      progress += 10;
     }
     outstream.write(buffer, 0, count);
    }
    outstream.flush();
   } finally {
    outstream.close();
   }
   System.out.println("Done");
  }
 }

 private static String cleanFilename(String filename) {
  for (char c : ILLEGAL_FILENAME_CHARACTERS) {
   filename = filename.replace(c, '_');
  }
  return filename;
 }

 private static URI getUri(String path, List<NameValuePair> qparams) throws URISyntaxException {
  URI uri = URIUtils.createURI(scheme, host, -1, "/" + path, URLEncodedUtils.format(qparams, DEFAULT_ENCODING), null);
  return uri;
 }

 private void setupLogging(Level myLevel, Level globalLevel) {
  changeFormatter(this);
  explicitlySetAllLogging(myLevel, globalLevel);
 }

 @Override
 public String format(LogRecord arg0) {
  return arg0.getMessage() + newline;
 }

 private static void changeFormatter(Formatter formatter) {
  Handler[] handlers = rootlog.getHandlers();
  for (Handler handler : handlers) {
   handler.setFormatter(formatter);
  }
 }

 private static void explicitlySetAllLogging(Level myLevel, Level globalLevel) {
  rootlog.setLevel(Level.ALL);
  for (Handler handler : rootlog.getHandlers()) {
   handler.setLevel(Level.ALL);
  }
  log.setLevel(myLevel);
  rootlog.setLevel(globalLevel);
 }

 private static String getStringFromInputStream(String encoding, InputStream instream) throws UnsupportedEncodingException, IOException {
  Writer writer = new StringWriter();

  char[] buffer = new char[1024];
  try {
   Reader reader = new BufferedReader(new InputStreamReader(instream, encoding));
   int n;
   while ((n = reader.read(buffer)) != -1) {
    writer.write(buffer, 0, n);
   }
  } finally {
   instream.close();
  }
  String result = writer.toString();
  return result;
 }
}

/**
 * <pre>
 * Exploded results from get_video_info:
 * 
 * fexp=909302
 * allow_embed=1
 * fmt_stream_map=35|http://v9.lscache8.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=35&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=9E0A8E67154145BCADEBCF844CC155282548288F.2BBD0B2E125E3E533D07866C7AE91B38DD625D30&factor=1.25&id=4ba2193f7c9127d2||tc.v9.cache8.c.youtube.com,34|http://v6.lscache3.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=6726793A7B041E6456B52C0972596D0D58974141.42B5A0573F62B85AEA7979E5EE1ADDD47EB9E909&factor=1.25&id=4ba2193f7c9127d2||tc.v6.cache3.c.youtube.com,18|http://v12.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=AE58398D4CC4D760C682D2A5B670B4047777FFF0.952E4FC4554E786FD937E7A89140E1F79B6DD8B7&factor=1.25&id=4ba2193f7c9127d2||tc.v12.cache7.c.youtube.com,5|http://v1.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=43434DCB6CFC463FF4522D9EE7CD019FE47237B1.C60A9522E361130938663AF2DAD83A5C2821AF5C&factor=1.25&id=4ba2193f7c9127d2||tc.v1.cache7.c.youtube.com
 * fmt_url_map=35|http://v9.lscache8.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=35&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=9E0A8E67154145BCADEBCF844CC155282548288F.2BBD0B2E125E3E533D07866C7AE91B38DD625D30&factor=1.25&id=4ba2193f7c9127d2,34|http://v6.lscache3.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=6726793A7B041E6456B52C0972596D0D58974141.42B5A0573F62B85AEA7979E5EE1ADDD47EB9E909&factor=1.25&id=4ba2193f7c9127d2,18|http://v12.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=AE58398D4CC4D760C682D2A5B670B4047777FFF0.952E4FC4554E786FD937E7A89140E1F79B6DD8B7&factor=1.25&id=4ba2193f7c9127d2,5|http://v1.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=43434DCB6CFC463FF4522D9EE7CD019FE47237B1.C60A9522E361130938663AF2DAD83A5C2821AF5C&factor=1.25&id=4ba2193f7c9127d2
 * allow_ratings=1
 * keywords=Stefan Molyneux,Luke Bessey,anarchy,stateless society,giant stone cow,the story of our unenslavement,market anarchy,voluntaryism,anarcho capitalism
 * track_embed=0
 * fmt_list=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0
 * author=lukebessey
 * muted=0
 * length_seconds=390
 * plid=AASZXXGQtTEDKwAw
 * ftoken=null
 * status=ok
 * watermark=http://s.ytimg.com/yt/swf/logo-vfl_bP6ud.swf,http://s.ytimg.com/yt/swf/hdlogo-vfloR6wva.swf
 * timestamp=1294526523
 * has_cc=False
 * fmt_map=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0
 * leanback_module=http://s.ytimg.com/yt/swfbin/leanback_module-vflJYyeZN.swf
 * hl=en_US
 * endscreen_module=http://s.ytimg.com/yt/swfbin/endscreen-vflk19iTq.swf
 * vq=auto
 * avg_rating=5.0
 * video_id=S6IZP3yRJ9I
 * token=vjVQa1PpcFNhI3jvw6hfEHivcKK-XY5gb-iszDMrooA=
 * thumbnail_url=http://i4.ytimg.com/vi/S6IZP3yRJ9I/default.jpg
 * title=The Story of Our Unenslavement - Animated
 * </pre>
 */

关于java - Youtube 数据 API : Get access to media stream and play (JAVA),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4700945/

有关java - Youtube 数据 API : Get access to media stream and play (JAVA)的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  3. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  6. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  7. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  8. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  9. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  10. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

随机推荐