[Android] cleartextTrafficPermitted on localhost must be enabled when call setUrl with headers on API >= 29
To Reproduce Steps to reproduce the behavior:
On an android 10 (possibly 9), call to AudioPlayer setUrl function will throw an error if the headers parameter is set, even with an empty map {}.
Error messages
I/ExoPlayerImpl(10242): Init 107a4fa [ExoPlayerLib/2.12.1] [a41, SM-A415F, samsung, 29]
D/skia (10242): SkJpegCodec::onGetPixels +
D/skia (10242): SkJpegCodec::onGetPixels -
I/System.out(10242): (HTTPLog)-Static: isSBSettingEnabled false
I/System.out(10242): (HTTPLog)-Static: isSBSettingEnabled false
I/System.out(10242): (HTTPLog)-Static: isSBSettingEnabled false
I/System.out(10242): (HTTPLog)-Static: isSBSettingEnabled false
E/ExoPlayerImplInternal(10242): Playback error
E/ExoPlayerImplInternal(10242): com.google.android.exoplayer2.ExoPlaybackException: Source error
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:554)
E/ExoPlayerImplInternal(10242): at android.os.Handler.dispatchMessage(Handler.java:103)
E/ExoPlayerImplInternal(10242): at android.os.Looper.loop(Looper.java:237)
E/ExoPlayerImplInternal(10242): at android.os.HandlerThread.run(HandlerThread.java:67)
E/ExoPlayerImplInternal(10242): Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$HttpDataSourceException: Unable to connect
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:309)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:199)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1013)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:415)
E/ExoPlayerImplInternal(10242): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/ExoPlayerImplInternal(10242): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/ExoPlayerImplInternal(10242): at java.lang.Thread.run(Thread.java:919)
E/ExoPlayerImplInternal(10242): Caused by: java.io.IOException: Cleartext HTTP traffic to 127.0.0.1 not permitted
E/ExoPlayerImplInternal(10242): at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:124)
E/ExoPlayerImplInternal(10242): at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:480)
E/ExoPlayerImplInternal(10242): at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:135)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.makeConnection(DefaultHttpDataSource.java:589)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.makeConnection(DefaultHttpDataSource.java:493)
E/ExoPlayerImplInternal(10242): at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:307)
E/ExoPlayerImplInternal(10242): ... 7 more
E/AudioPlayer(10242): TYPE_SOURCE: Unable to connect
I/flutter (10242): #0 AudioPlayer._load (package:just_audio/just_audio.dart:498:9)
I/flutter (10242): <asynchronous suspension>
I/flutter (10242): #1 AudioPlayer.load (package:just_audio/just_audio.dart:456:30)
I/flutter (10242): #2 AudioPlayer.setUrl (package:just_audio/just_audio.dart:421:7)
I/flutter (10242): #3 AudioPlayerTask.onPlay (package:bide_et_musique/player.dart:162:26)
I/flutter (10242): <asynchronous suspension>
I/flutter (10242): #4 AudioServiceBackground.run.<anonymous closure> (package:audio_service/audio_service.dart:1229:25)
I/flutter (10242): #5 MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:430:55)
I/flutter (10242): #6 MethodChannel.setMethodCallHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:383:34)
I/flutter (10242): #7 _DefaultBinaryMessenger.handlePlatformMessage (package:flutter/src/services/binding.dart:283:33)
I/flutter (10242): #8 _invoke3.<anonymous closure> (dart:ui/hooks.dart:280:15)
I/flutter (10242): #9 _rootRun (dart:async/zone.dart:1190:13)
I/flutter (10242): #10 _CustomZone.run (dart:async/zone.dart:1093:19)
I/flutter (10242): #11 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
I/flutter (10242): #12 _invoke3 (dart:
E/flutter (10242): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: PlatformException((0) Source error, null, null, null)
E/flutter (10242): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:582:7)
E/flutter (10242): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:159:18)
E/flutter (10242): <asynchronous suspension>
E/flutter (10242): #2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:332:12)
E/flutter (10242): #3 AudioService.play (package:audio_service/audio_service.dart:928:20)
E/flutter (10242): #4 _SongPlayerWidgetState.play (package:bide_et_musique/widgets/song_app_bar.dart:404:24)
E/flutter (10242): <asynchronous suspension>
E/flutter (10242): #5 _SongPlayerWidgetState.build.<anonymous closure>.<anonymous closure> (package:bide_et_musique/widgets/song_app_bar.dart:344:34)
E/flutter (10242): #6 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
E/flutter (10242): #7 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1111:38)
E/flutter (10242): #8 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
E/flutter (10242): #9 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:598:11)
E/flutter (10242): #10 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:287:5)
E/flutter (10242): #11 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:222:7)
E/flutter (10242): #12 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:476:9)
E/flutter (10242): #13 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:77:12)
E/flutter (10242): #14 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:122:9)
E/flutter (10242): #15 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
E/flutter (10242): #16 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:120:18)
E/flutter (10242): #17 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:106:7)
E/flutter (10242): #18 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:358:19)
E/flutter (10242): #19 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
E/flutter (10242): #20 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
E/flutter (10242): #21 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
E/flutter (10242): #22 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
E/flutter (10242): #23 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
E/flutter (10242): #24 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (10242): #25 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (10242): #26 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (10242): #27 _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter (10242): #28 _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
E/flutter (10242):
E/flutter (10242): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: PlatformException(0, Source error, null, null)
Smartphone (please complete the following information):
- Device: Samsung A41
- OS: Android 10
Flutter SDK version
[✓] Flutter (Channel stable, 1.22.4, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
Additional context
There where no issu on Android 8. So I believe this error is thrown due to new security restrictions.
I fixed the problem by adding 127.0.0.1 in a network_security_config.xml as explained at https://stackoverflow.com/questions/45940861/android-8-cleartext-http-traffic-not-permitted
Please check how just_audio use the localhost adress to prevent this exception on modern android devices.
BR
I used the android:usesCleartextTraffic="true" manifest approach to solve this issue on Android 11. This isn't really a just_audio bug but related to how it cleverly creates an internal proxy to send headers and the proxy itself is using http not https.
Oh, that's interesting. My assumption was that using HTTP within the same device would be safe from snooping, and I guess that's true on an unrooted phone.
After checking the SDK, there is an API to create an HTTPS server (SecureServerSocket) which I should probably use.
There is also HttpServer.bindSecure. I think the issue here will be that iOS doesn't work well with self-signed server certificates:
https://stackoverflow.com/questions/38217551/how-can-i-use-an-avplayer-with-https-and-self-signed-server-certificates
For apps where security is a relevant concern, I may look into another solution for headers described here:
https://exceptionshub.com/send-headers-with-avplayer-request-in-ios.html
I have avoided using the private API since that may get your app rejected. The two alternatives proposed were to use a proxy (the current solution adopted by just_audio) or a resourceLoader delegate, which may be the right direction to go in.
I'm having this issue and getting Cleartext HTTP traffic to 127.0.0.1 not permitted when trying to load a local stream
any update on it?