currently I'm building a demo where I can play an audio file and control it in the background using _audio_service_ plugin beside I can download this file using the _flutter_downloader_ plugin, the file plays well but when I try to download the file the app crashes, seems that there are conflict or some special configs that I should do in this case, here are the logs and the specs
flutter version: 1.5.4-hotfix-2
in pubspec.yaml
flutter_downloader: ^1.3.0
audio_service: ^0.5.2
when I press on the _download file_ button the app crash with this log
Process: com.ryanheise.audioserviceexample, PID: 28080
E/AndroidRuntime(28080): java.lang.NullPointerException: Attempt to invoke virtual method 'void com.ryanheise.audioservice.AudioServicePlugin$BackgroundHandler.init(io.flutter.plugin.common.PluginRegistry$Registrar)' on a null object reference
E/AndroidRuntime(28080): at com.ryanheise.audioservice.AudioServicePlugin.registerWith(AudioServicePlugin.java:71)
E/AndroidRuntime(28080): at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(GeneratedPluginRegistrant.java:18)
E/AndroidRuntime(28080): at com.ryanheise.audioserviceexample.MainApplication.registerWith(MainApplication.java:18)
E/AndroidRuntime(28080): at vn.hunghd.flutterdownloader.DownloadWorker.startBackgroundIsolate(DownloadWorker.java:124)
E/AndroidRuntime(28080): at vn.hunghd.flutterdownloader.DownloadWorker.access$000(DownloadWorker.java:59)
E/AndroidRuntime(28080): at vn.hunghd.flutterdownloader.DownloadWorker$1.run(DownloadWorker.java:97)
E/AndroidRuntime(28080): at android.os.Handler.handleCallback(Handler.java:869)
E/AndroidRuntime(28080): at android.os.Handler.dispatchMessage(Handler.java:101)
E/AndroidRuntime(28080): at android.os.Looper.loop(Looper.java:206)
E/AndroidRuntime(28080): at android.app.ActivityThread.main(ActivityThread.java:6749)
E/AndroidRuntime(28080): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(28080): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
E/AndroidRuntime(28080): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:845)
Here's the source code
void initState() {
super.initState();
initDownloader();
WidgetsBinding.instance.addObserver(this);
listenToDownloadUpdates();
//connect();
}
initDownloader() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize();
}
listenToDownloadUpdates(){
IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
print('progress::: $progress');
});
}
RaisedButton buildDownloadButton(){
return RaisedButton(
child: Text('download file'),
onPressed: () async {
String downloadDirectory = await getDownloadDirPath();
print(downloadDirectory);
FlutterDownloader.registerCallback(downloadCallback);
final taskId = await FlutterDownloader.enqueue(
url: "https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3",
savedDir: downloadDirectory,
showNotification: false,
fileName: basename("https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"),
);
},
);
}
static Future<String> getDownloadDirPath() async {
Directory docDir = await getApplicationDocumentsDirectory();
String dirPath = docDir.path + '/downloads';
await Directory(dirPath).createSync();
return dirPath;
}
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
for MainApplication.java
package com.ryanheise.audioserviceexample;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.app.FlutterApplication;
import io.flutter.plugins.GeneratedPluginRegistrant;
import com.ryanheise.audioservice.AudioServicePlugin;
public class MainApplication extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
@Override
public void onCreate() {
super.onCreate();
AudioServicePlugin.setPluginRegistrantCallback(this);
}
@Override
public void registerWith(PluginRegistry registry) {
GeneratedPluginRegistrant.registerWith(registry);
}
}
for AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ryanheise.audioserviceexample">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name=".MainApplication"
android:label="Audio Service Demo"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="com.ryanheise.audioservice.AudioService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
</application>
</manifest>
I am aware of the conflict although the first step is to get v2 embedding to work (which should in itself help), and then address the conflict.
Can you try the latest Git commit which adds preliminary v2 embedding support?
@ryanheise
To make sure that I'm understanding you correctly, you mean that I use the latest version of audio_service, right ?
if I'm understanding right this requires that I'll another version of flutter, right ?
Hi @hesham91fci
Please use latest git commit of audio_service plugin in your project. And also update flutter to the stable channel which is version 1.12.
Hope this helps.
Also report on whether the conflict is resolved.
@rohansohonee @ryanheise
Currently I've migrated the example to flutter 1.12.13 with audio_service 0.5.7
but nothing resolved, the app crashes, beside no logs can be seen now 馃槃 馃槃
Hi @hesham91fci
Please use latest git commit of audio_service.
Do not use 0.5.7 as it does not support v2 embedding
@rohansohonee @ryanheise
perfect, it worked with no problem
Great. I will try to push out a new version ASAP, although I'm just waiting on confirmation that this code doesn't break anyone's project that is pre v2 embedding.
This is now published in 0.6.0.