简体   繁体   English

flutter audio_service 发生无法启动活动

[英]flutter audio_service Unable to start activity occured

I am using audio_service in my flutter app.我在我的颤振应用程序中使用 audio_service。 Since 1.18.6, I got this error in firebase crashlytics and alot of user complained that player is stopped playing if they open other app.从 1.18.6 开始,我在 firebase crashlytics 中遇到了这个错误,很多用户抱怨如果他们打开其他应用程序,播放器就会停止播放。 So when I tested, I play the mp3 and open facebook, but not stopped immediately but stopped for a while and app is crash.所以当我测试时,我播放了 mp3 并打开了 facebook,但没有立即停止而是停止了一段时间,应用程序崩溃了。 I found the following error report a lot.我发现下面的错误报告很多。

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{org.thitsarparami.app/com.ryanheise.audioservice.AudioServiceActivity}: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/org.thitsarparami.app-a-dcbjkGZG7bhB8y1Z4zZw==/base.apk"],nativeLibraryDirectories=[/data/app/org.thitsarparami.app-a-dcbjkGZG7bhB8y1Z4zZw==/lib/arm64, /system/lib64, /hw_product/lib64, /system/product/lib64]]] couldn't find "libflutter.so"
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3897)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4076)
       at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
       at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2473)
       at android.os.Handler.dispatchMessage(Handler.java:110)
       at android.os.Looper.loop(Looper.java:219)
       at android.app.ActivityThread.main(ActivityThread.java:8349)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

Handler处理程序

import 'dart:async';
import 'dart:ui';
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:just_audio/just_audio.dart';
import 'package:rxdart/rxdart.dart';

class QueueState {
  static const QueueState empty =
      QueueState([], 0, [], AudioServiceRepeatMode.none);

  final List<MediaItem> queue;
  final int? queueIndex;
  final List<int>? shuffleIndices;
  final AudioServiceRepeatMode repeatMode;

  const QueueState(
      this.queue, this.queueIndex, this.shuffleIndices, this.repeatMode);

  bool get hasPrevious =>
      repeatMode != AudioServiceRepeatMode.none || (queueIndex ?? 0) > 0;
  bool get hasNext =>
      repeatMode != AudioServiceRepeatMode.none ||
      (queueIndex ?? 0) + 1 < queue.length;

  List<int> get indices =>
      shuffleIndices ?? List.generate(queue.length, (i) => i);
}

Future<AudioPlayerHandler> initAudioService() async {
  return await AudioService.init(
    builder: () => AudioPlayerHandlerImpl(),
    config: const AudioServiceConfig(
      androidNotificationChannelId: 'org.thitsarparami.app.audio',
      androidNotificationChannelName: 'သစ္စာပါရမီ',
      notificationColor: Color(0xff1751af),
      androidNotificationIcon: 'mipmap/ic_launcher',
      androidNotificationOngoing: true,
      androidStopForegroundOnPause: true,
    ),
  );
}

/// An [AudioHandler] for playing a list of podcast episodes.
///
/// This class exposes the interface and not the implementation.
abstract class AudioPlayerHandler implements AudioHandler {
  Stream<QueueState> get queueState;
  Future<void> moveQueueItem(int currentIndex, int newIndex);
  ValueStream<double> get volume;
  Future<void> setVolume(double volume);
  ValueStream<double> get speed;
}

/// The implementation of [AudioPlayerHandler].
///
/// This handler is backed by a just_audio player. The player's effective
/// sequence is mapped onto the handler's queue, and the player's state is
/// mapped onto the handler's state.
class AudioPlayerHandlerImpl extends BaseAudioHandler
    with SeekHandler
    implements AudioPlayerHandler {
  // ignore: close_sinks
  final BehaviorSubject<List<MediaItem>> _recentSubject =
      BehaviorSubject.seeded(<MediaItem>[]);
  final _mediaLibrary = MediaLibrary();
  final _player = AudioPlayer();
  final _playlist = ConcatenatingAudioSource(children: []);
  @override
  final BehaviorSubject<double> volume = BehaviorSubject.seeded(1.0);
  @override
  final BehaviorSubject<double> speed = BehaviorSubject.seeded(1.0);
  final _mediaItemExpando = Expando<MediaItem>();

  /// A stream of the current effective sequence from just_audio.
  Stream<List<IndexedAudioSource>> get _effectiveSequence => Rx.combineLatest3<
              List<IndexedAudioSource>?,
              List<int>?,
              bool,
              List<IndexedAudioSource>?>(_player.sequenceStream,
          _player.shuffleIndicesStream, _player.shuffleModeEnabledStream,
          (sequence, shuffleIndices, shuffleModeEnabled) {
        if (sequence == null) return [];
        if (!shuffleModeEnabled) return sequence;
        if (shuffleIndices == null) return null;
        if (shuffleIndices.length != sequence.length) return null;
        return shuffleIndices.map((i) => sequence[i]).toList();
      }).whereType<List<IndexedAudioSource>>();

  /// Computes the effective queue index taking shuffle mode into account.
  int? getQueueIndex(
      int? currentIndex, bool shuffleModeEnabled, List<int>? shuffleIndices) {
    final effectiveIndices = _player.effectiveIndices ?? [];
    final shuffleIndicesInv = List.filled(effectiveIndices.length, 0);
    for (var i = 0; i < effectiveIndices.length; i++) {
      shuffleIndicesInv[effectiveIndices[i]] = i;
    }
    return (shuffleModeEnabled &&
            ((currentIndex ?? 0) < shuffleIndicesInv.length))
        ? shuffleIndicesInv[currentIndex ?? 0]
        : currentIndex;
  }

  /// A stream reporting the combined state of the current queue and the current
  /// media item within that queue.
  @override
  Stream<QueueState> get queueState =>
      Rx.combineLatest3<List<MediaItem>, PlaybackState, List<int>, QueueState>(
          queue,
          playbackState,
          _player.shuffleIndicesStream.whereType<List<int>>(),
          (queue, playbackState, shuffleIndices) => QueueState(
                queue,
                playbackState.queueIndex,
                playbackState.shuffleMode == AudioServiceShuffleMode.all
                    ? shuffleIndices
                    : null,
                playbackState.repeatMode,
              )).where((state) =>
          state.shuffleIndices == null ||
          state.queue.length == state.shuffleIndices!.length);

  @override
  Future<void> setShuffleMode(AudioServiceShuffleMode shuffleMode) async {
    final enabled = shuffleMode == AudioServiceShuffleMode.all;
    if (enabled) {
      await _player.shuffle();
    }
    playbackState.add(playbackState.value.copyWith(shuffleMode: shuffleMode));
    await _player.setShuffleModeEnabled(enabled);
  }

  @override
  Future<void> setRepeatMode(AudioServiceRepeatMode repeatMode) async {
    playbackState.add(playbackState.value.copyWith(repeatMode: repeatMode));
    await _player.setLoopMode(LoopMode.values[repeatMode.index]);
  }

  @override
  Future<void> setSpeed(double speed) async {
    this.speed.add(speed);
    await _player.setSpeed(speed);
  }

  @override
  Future<void> setVolume(double volume) async {
    this.volume.add(volume);
    await _player.setVolume(volume);
  }

  AudioPlayerHandlerImpl() {
    _init();
  }

  Future<void> _init() async {
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration.speech());
    // Broadcast speed changes. Debounce so that we don't flood the notification
    // with updates.
    speed.debounceTime(const Duration(milliseconds: 250)).listen((speed) {
      playbackState.add(playbackState.value.copyWith(speed: speed));
    });
    // Load and broadcast the initial queue
    await updateQueue(_mediaLibrary.items[MediaLibrary.albumsRootId]!);

    // For Android 11, record the most recent item so it can be resumed.
    mediaItem
        .whereType<MediaItem>()
        .listen((item) => _recentSubject.add([item]));
// Broadcast media item changes.
    Rx.combineLatest4<int?, List<MediaItem>, bool, List<int>?, MediaItem?>(
        _player.currentIndexStream,
        queue,
        _player.shuffleModeEnabledStream,
        _player.shuffleIndicesStream,
        (index, queue, shuffleModeEnabled, shuffleIndices) {
      final queueIndex =
          getQueueIndex(index, shuffleModeEnabled, shuffleIndices);
      return (queueIndex != null && queueIndex < queue.length)
          ? queue[queueIndex]
          : null;
    }).whereType<MediaItem>().distinct().listen(mediaItem.add);

    // Rx.combineLatest5<int?, List<MediaItem>, bool, List<int>?, Duration?,
    //         MediaItem?>(
    //     _player.currentIndexStream,
    //     queue,
    //     _player.shuffleModeEnabledStream,
    //     _player.shuffleIndicesStream,
    //     _player.durationStream, // <- add listening to durationStream here
    //     (index, queue, shuffleModeEnabled, shuffleIndices, duration) {
    //   if (kDebugMode) {
    //     print("Init ${mediaItem.value?.title} - $duration");
    //   }
    //   final queueIndex =
    //       getQueueIndex(index, shuffleModeEnabled, shuffleIndices);

    //   return (queueIndex != null && queueIndex < queue.length)
    //       ? queue[queueIndex].copyWith(
    //           duration: duration) // <- sink mediaItem provided with duration
    //       : null;
    // }).whereType<MediaItem>().distinct().listen(mediaItem.add);

    // Propagate all events from the audio player to AudioService clients.
    _player.playbackEventStream.listen(_broadcastState);
    _player.shuffleModeEnabledStream
        .listen((enabled) => _broadcastState(_player.playbackEvent));
    // In this example, the service stops when reaching the end.
    _player.processingStateStream.listen((state) {
      if (state == ProcessingState.completed) {
        stop();
        _player.seek(Duration.zero, index: 0);
      }
    });
    // In this example, the service stops when reaching the end.
    // Broadcast the current queue.
    _effectiveSequence
        .map((sequence) =>
            sequence.map((source) => _mediaItemExpando[source]!).toList())
        .pipe(queue);
    // Load the playlist.
    _playlist.addAll(queue.value.map(_itemToSource).toList());
    await _player.setAudioSource(_playlist, preload: false);
  }

  @override
  Future<List<MediaItem>> getChildren(String parentMediaId,
      [Map<String, dynamic>? options]) async {
    switch (parentMediaId) {
      case AudioService.recentRootId:
        // When the user resumes a media session, tell the system what the most
        // recently played item was.
        return _recentSubject.value;
      default:
        // Allow client to browse the media library.
        return _mediaLibrary.items[parentMediaId]!;
    }
  }

  @override
  ValueStream<Map<String, dynamic>> subscribeToChildren(String parentMediaId) {
    switch (parentMediaId) {
      case AudioService.recentRootId:
        final stream = _recentSubject.map((_) => <String, dynamic>{});
        return _recentSubject.hasValue
            ? stream.shareValueSeeded(<String, dynamic>{})
            : stream.shareValue();
      default:
        return Stream.value(_mediaLibrary.items[parentMediaId])
            .map((_) => <String, dynamic>{})
            .shareValue();
    }
  }

  //  AudioSource _itemToSource(MediaItem mediaItem) {
  //   final audioSource =
  //       AudioSource.uri(Uri.parse(mediaItem.extras?['url']), tag: mediaItem);
  //   _mediaItemExpando[audioSource] = mediaItem;
  //   return audioSource;
  // }

  UriAudioSource _itemToSource(MediaItem mediaItem) {
    final uri = mediaItem.extras == null
        ? Uri.parse("https://edge.mixlr.com/channel/nmtev")
        : Uri.parse(mediaItem.extras?['url']);

    final audioSource = AudioSource.uri(uri, tag: mediaItem);
    _mediaItemExpando[audioSource] = mediaItem;
    return audioSource;
  }

  List<AudioSource> _itemsToSources(List<MediaItem> mediaItems) =>
      mediaItems.map(_itemToSource).toList();

  @override
  Future<void> addQueueItem(MediaItem mediaItem) async {
    await _playlist.add(_itemToSource(mediaItem));
  }

  @override
  Future<void> addQueueItems(List<MediaItem> mediaItems) async {
    await _playlist.addAll(_itemsToSources(mediaItems));
  }

  @override
  Future<void> insertQueueItem(int index, MediaItem mediaItem) async {
    await _playlist.insert(index, _itemToSource(mediaItem));
  }

  @override
  Future<void> updateQueue(List<MediaItem> queue) async {
    await _playlist.clear();
    await _playlist.addAll(_itemsToSources(queue));
  }

  Future<void> emptyPlaylist() async {
    while (queue.value.isNotEmpty) {
      final lastIndex = queue.value.length - 1;
      if (lastIndex < 0) return;
      removeQueueItemAt(lastIndex);
    }
  }

  @override
  // ignore: avoid_renaming_method_parameters
  Future<void> updateMediaItem(MediaItem newMediaItem) async {
    // rewrite updateMediaItem function because it is need to notify the mediaItem about favourite or unfavourite.
    final index = queue.value.indexWhere((item) => item.id == newMediaItem.id);
    if (index != -1) {
      queue.value[index] = newMediaItem;
      _playlist.children[index] = _itemToSource(newMediaItem);
      _player.sequenceState!.sequence[index] = _itemToSource(newMediaItem);
      _mediaItemExpando[_player.sequence![index]] = newMediaItem;
      mediaItem.add(newMediaItem);
    }
  }

  // @override
  // Future<void> updateMediaItem(MediaItem mediaItem) async {
  //   final index = queue.value.indexWhere((item) => item.id == mediaItem.id);
  //   _mediaItemExpando[_player.sequence![index]] = mediaItem;
  // }

  @override
  Future<void> removeQueueItem(MediaItem mediaItem) async {
    final index = queue.value.indexOf(mediaItem);
    await _playlist.removeAt(index);
  }

  @override
  Future<void> removeQueueItemAt(int index) async {
    await _playlist.removeAt(index);
  }

  @override
  Future<void> moveQueueItem(int currentIndex, int newIndex) async {
    await _playlist.move(currentIndex, newIndex);
  }

  @override
  Future<void> skipToNext() => _player.seekToNext();

  @override
  Future<void> skipToPrevious() => _player.seekToPrevious();

  @override
  Future<void> skipToQueueItem(int index) async {
    if (index < 0 || index >= _playlist.children.length) return;
    // This jumps to the beginning of the queue item at [index].
    _player.seek(Duration.zero,
        index: _player.shuffleModeEnabled
            ? _player.shuffleIndices![index]
            : index);
  }

  @override
  Future<void> play() => _player.play();

  @override
  Future<void> pause() => _player.pause();

  @override
  Future<void> seek(Duration position) async {
    await _player.seek(position);
  }

  @override
  Future<void> stop() async {
    await _player.stop();
    await playbackState.firstWhere(
        (state) => state.processingState == AudioProcessingState.idle);
  }

  @override
  Future<void> fastForward() async {
    _player.seek(Duration(seconds: _player.position.inSeconds + 15));
  }

  @override
  Future<void> rewind() async {
    _player.seek(Duration(seconds: _player.position.inSeconds - 15));
  }

  /// Broadcasts the current state to all clients.
  void _broadcastState(PlaybackEvent event) {
    final playing = _player.playing;
    final queueIndex = getQueueIndex(
        event.currentIndex, _player.shuffleModeEnabled, _player.shuffleIndices);
    playbackState.add(playbackState.value.copyWith(
      controls: [
        MediaControl.skipToPrevious,
        if (playing) MediaControl.pause else MediaControl.play,
        MediaControl.stop,
        MediaControl.skipToNext,
      ],
      systemActions: const {
        MediaAction.seek,
        MediaAction.seekForward,
        MediaAction.seekBackward,
      },
      androidCompactActionIndices: const [0, 1, 3],
      processingState: const {
        ProcessingState.idle: AudioProcessingState.idle,
        ProcessingState.loading: AudioProcessingState.loading,
        ProcessingState.buffering: AudioProcessingState.buffering,
        ProcessingState.ready: AudioProcessingState.ready,
        ProcessingState.completed: AudioProcessingState.completed,
      }[_player.processingState]!,
      playing: playing,
      updatePosition: _player.position,
      bufferedPosition: _player.bufferedPosition,
      speed: _player.speed,
      queueIndex: queueIndex,
    ));
  }
}

// Provides access to a library of media items. In your app, this could come
// from a database or web service.
class MediaLibrary {
  static const albumsRootId = 'albums';

  final items = <String, List<MediaItem>>{
    AudioService.browsableRootId: const [
      MediaItem(
        id: albumsRootId,
        title: "Albums",
        playable: false,
      ),
    ],
    albumsRootId: [
      const MediaItem(
        id: 'radio',
        album: 'Radio',
        title: 'သစ္စာပါရမီ',
        artist: '၂၄ နာရီရေဒီယို',
        duration: Duration(hours: 24),
        extras: {'url': 'https://edge.mixlr.com/channel/nmtev'},
      ),
      // MediaItem(
      //   id: 'radio',
      //   album: 'Radio',
      //   title: 'အဖွင့်',
      //   artist: 'မဟာဂန္ဓာရုံဆရာတော်ကြီး',
      //   artUri: Uri.parse(
      //       "https://fileapi.thitsarparami.org/storage/images/cl1b0zkn902jdt0v702enhgzz/cl1b0zkn902jdt0v702enhgzz.png"),
      //   extras: {
      //     'url':
      //         'https://media.thitsarparami.org/song/cl1b0zkn902jdt0v702enhgzz/cl1b0zkns02mut0v77ubi3iqb/cl1b0zkns02mwt0v7dcvahq4z.mp3'
      //   },
      // ),
    ],
  };
}

flutter doctor扑医生

[✓] Flutter (Channel stable, 3.0.5, on macOS 12.4 21F79 darwin-x64, locale en-GB) • Flutter version 3.0.5 at /Users/aungmyooo/Development/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision f1875d570e (5 days ago), 2022-07-13 11:24:16 -0700 • Engine revision e85ea0e79c • Dart version 2.17.6 • DevTools version 2.12.2 [✓] Flutter(Channel stable,3.0.5,macOS 12.4 21F79 darwin-x64,locale en-GB) • Flutter 版本 3.0.5,位于 /Users/aungmyooo/Development/flutter • 上游存储库https://github.com /flutter/flutter.git • 框架修订版 f1875d570e(5 天前),2022-07-13 11:24:16 -0700 • 引擎修订版 e85ea0e79c • Dart 版本 2.17.6 • DevTools 版本 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0) • Android SDK at /Users/aungmyooo/Library/Android/sdk • Platform android-33, build-tools 31.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822) • All Android licenses accepted. [✓] Android 工具链 - 为 Android 设备开发(Android SDK 版本 31.0.0) • Android SDK 位于 /Users/aungmyooo/Library/Android/sdk • 平台 android-33,构建工具 31.0.0 • Java 二进制位于:/ Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java 版本 OpenJDK 运行时环境(内部版本 11.0.11+0-b60-7590822) • 接受所有 Android 许可证。

[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1) • Xcode at /Applications/Xcode.app/Contents/Developer • CocoaPods version 1.11.3 [✓] Xcode - 为 iOS 和 macOS 开发 (Xcode 13.4.1) • Xcode 在 /Applications/Xcode.app/Contents/Developer • CocoaPods 版本 1.11.3

[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Chrome - 为网络开发 • Chrome 位于 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822) [✓] Android Studio(版本 2021.1) • Android Studio 位于 /Applications/Android Studio.app/Contents • Flutter 插件可以从以下位置安装:🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart 插件可以从以下位置安装:🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java 版本 OpenJDK 运行时环境(内部版本 11.0.11+0-b60-7590822)

[✓] VS Code (version 1.69.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.44.0 [✓] VS Code(版本 1.69.1) • /Applications/Visual Studio Code.app/Contents 中的 VS Code • Flutter 扩展版本 3.44.0

[✓] Connected device (3 available) • iPhone (mobile) • 06e02964e429eeebf29550b03ef955abe09891ef • ios • iOS 15.5 19F77 • macOS (desktop) • macos • darwin-x64 • macOS 12.4 21F79 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 103.0.5060.114 [✓] 连接设备(3 个可用) • iPhone(移动) • 06e02964e429eeebf29550b03ef955abe09891ef • ios • iOS 15.5 19F77 • macOS(桌面) • macos • darwin-x64 • macOS 12.4 21F79 darwin-x64 • Chrome(网络) • chrome • web- javascript • 谷歌浏览器 103.0.5060.114

[✓] HTTP Host Availability • All required HTTP hosts are available [✓] HTTP 主机可用性 • 所有必需的 HTTP 主机都可用

This is the salient part of the error message:这是错误消息的重要部分:

Fatal Exception: java.lang.RuntimeException: Unable to start activity ... 
... couldn't find "libflutter.so"

This appears to be a build-time issue.这似乎是一个构建时问题。

It's been reported multiple different times over multiple different versions.已经在多个不同版本中多次报告了它。 I see several "workarounds" ... but no "fix".我看到了几个“解决方法”......但没有“修复”。

Specifically:具体来说:

https://github.com/flutter/flutter/issues/32756 https://github.com/flutter/flutter/issues/32756

Seems like uninstalling the app and reinstalling fixed it, error occured without changing anything in the code, just opened up Android studio again and pressed the run button...好像卸载应用程序并重新安装修复它,发生错误而没有更改代码中的任何内容,只是再次打开Android工作室并按下运行按钮......

See also:也可以看看:

https://stackoverflow.com/a/65032771/421195 https://stackoverflow.com/a/65032771/421195

Flutter does not currently support building for x86 Android (See Issue 9253 ). Flutter 目前不支持为 x86 Android 构建(参见问题 9253 )。

Add following code under the buildTypes in android\app\build.gradle在 android\app\build.gradle 的 buildTypes 下添加以下代码

buildTypes { release { ndk { abiFilters 'armeabi-v7a','arm64-v8a','x86_64' } } }

... and ... ... 和 ...

https://stackoverflow.com/a/69998842/421195 https://stackoverflow.com/a/69998842/421195

In app level build.gradle following line should be added在应用程序级别 build.gradle 应添加以下行

defaultConfig { ... ndk { abiFilters "armeabi", "x86", "armeabi-v7a","x86_64", "mips", "mips64", "arm64-v8a" } }

SUGGESTION: Review the threads, post back and let us know if any of the suggestions worked for you.建议:查看主题,回帖并让我们知道是否有任何建议对您有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM