weex开发后台音乐播放功能带自定义通知栏

 

找遍weex及相应第三方框架,没发现有支持音乐播放的组件标签,则自己动手实现这一功能

效果如图(具体代码及样式在这里不提供)

通知栏

条件:

    1.使用基于weex的第三方框架eros

    2.会module扩展开发

    3.有java及android开发基础

 

正文开始:

一.开发service

 

public class MusicService extends Service {

    public final IBinder binder = new MyBinder();
    public class MyBinder extends Binder{
       public MusicService getService() {
            return MusicService.this;
        }
    }
    public static MediaPlayer mp = new MediaPlayer();
    public MusicService() {

    }

    public void setVideoUrl(Context context, String videoUrl){
        try {
            YhTools.Log(videoUrl);
            mp.reset();
            Uri uri = Uri.parse(videoUrl);
            mp.setDataSource(context,uri);
            mp.prepare();
        } catch (Exception e) {
            YhTools.Log("can't get to the song");
            e.printStackTrace();
        }
    }

    public void start() {
        mp.start();
    }
    public boolean isPlaying() {
        return mp.isPlaying();
    }
    public void playOrPause() {
        if(mp.isPlaying()){
            mp.pause();
        } else {
            mp.start();
        }
    }
    public void stop() {
        if(mp != null) {
            mp.stop();
            try {
                mp.prepare();
                mp.seekTo(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onDestroy() {
        mp.stop();
        mp.release();
        super.onDestroy();
    }

    /**
     * onBind 是 Service 的虚方法,因此我们不得不实现它。
     * 返回 null,表示客服端不能建立到此服务的连接。
     */
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

二.在Application中添加全局静态变量

 

public class App extends BMWXApplication {
 private static Context appContext;
 private static MusicService musicService = null;
 private static LessonInfo lessonInfo = null;
  .....此省略非重要代码

  @Override
  public void onCreate() {
    super.onCreate();
    try {
        WXSDKEngine.registerModule("MusicModule", MusicModule.class);
    } catch (WXException e) {
        e.printStackTrace();
    }
    .....此省略非重要代码
    appContext = getApplicationContext();
}
.....此省略非重要代码

public static Context getContext() {
    return appContext;
}
public static void setMusicService(MusicService service){
    musicService = service;
}
public static MusicService getMusicService(){
    return musicService;
}

public static void setLessonInfo(LessonInfo lesson){
    lessonInfo = lesson;
}

public static LessonInfo getLessonInfo(){
    return lessonInfo;
}
}

 

三.module模块开发

public class MusicModule extends WXModule {
    private static final String TAG = "ProgressNotification";
    public final static String INTENT_BUTTONID_TAG = "ButtonId";
    private static RemoteViews mRemoteViews = null;
    private static NotificationManager notificationManager = null;
    private static Notification notification = null;
    private static NotificationCompat.Builder builder = null;

    /**
     * 通知栏按钮点击事件对应的ACTION(标识广播)
     */
    public final static String ACTION_BUTTON = "com.notification.intent.action.ButtonClick";
    /**
     * 通知栏按钮广播
     */
    public static ButtonBroadcastReceiver receiver;
    /**
     * 播放/暂停 按钮点击 ID
     */
    public final static int BUTTON_PALY_ID = 1;
    public final static int BUTTON_NEXT_ID = 2;
    public final static int BUTTON_CLOSE_ID = 3;
    private final int NOTIFICATION_ID = 0xa01;
    private final int REQUEST_CODE = 0xb01;

    private Context getContext(){
        return App.getContext();
        //return mWXSDKInstance.getContext();
        //注意这里,不用mWXSDKInstance.getContext(),用是用App.getContext(),当weex页面切换时,操作还是同一个对像
    }


    private ServiceConnection sc = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            App.setMusicService(((MusicService.MyBinder) iBinder).getService());
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            App.setMusicService(null);
        }
    };


    private void bindServiceConnection() {
        Intent intent = new Intent(getContext(), MusicService.class);
        getContext().startService(intent);
        getContext().bindService(intent, sc, Activity.BIND_AUTO_CREATE);
    }

    private boolean isPlaying() {
        boolean isPlaying = false;
        if (App.getMusicService() != null) {
            isPlaying = App.getMusicService().isPlaying();
        }
        return isPlaying;
    }

    private void setNogification() {
        final LessonInfo lesson = App.getLessonInfo();
        if (lesson != null) {
            //导步获取通知栏中的图片
            new AsyncTask<String, Void, Bitmap>() {
                @Override
                protected Bitmap doInBackground(String... params) {
                    try {
                        URL url = new URL(params[0]);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        conn.setConnectTimeout(6000);//设置超时
                        conn.setDoInput(true);
                        conn.setUseCaches(false);//不缓存
                        conn.connect();
                        int code = conn.getResponseCode();
                        Bitmap bitmap = null;
                        if (code == 200) {
                            InputStream is = conn.getInputStream();//获得图片的数据流
                            bitmap = BitmapFactory.decodeStream(is);
                        }
                        return bitmap;
                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                        return null;
                    } catch (IOException e) {
                        e.printStackTrace();
                        return null;
                    }
                }

                @Override
                protected void onPostExecute(Bitmap result) {
                    super.onPostExecute(result);
                    if (result != null) {
                        showNotification(lesson, result);
                    }
                }
            }.execute(lesson.getThumb());
        }
    }

    private void showNotification(LessonInfo lesson, Bitmap bitmap) {
        int playIndex = lesson.getIndex();

        if(notificationManager == null || builder==null || mRemoteViews==null) {
            notificationManager = (NotificationManager) getContext().getSystemService(NOTIFICATION_SERVICE);
            builder = new NotificationCompat.Builder(getContext());
            mRemoteViews = new RemoteViews(getContext().getPackageName(), R.layout.notification_music);
        }
        //以上设置防止多次注册事件
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            if (receiver == null){
                mRemoteViews = new RemoteViews(getContext().getPackageName(), R.layout.notification_music);
                //注册广播
                receiver = new ButtonBroadcastReceiver();
                IntentFilter intentFilter = new IntentFilter();
                intentFilter.addAction(ACTION_BUTTON);
                getContext().registerReceiver(receiver, intentFilter);
                //设置点击的事件
                Intent buttonIntent = new Intent(ACTION_BUTTON);
                /* 播放/暂停  按钮 */
                buttonIntent.putExtra(INTENT_BUTTONID_TAG, BUTTON_PALY_ID);
                PendingIntent intent_paly = PendingIntent.getBroadcast(getContext(), BUTTON_PALY_ID, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                mRemoteViews.setOnClickPendingIntent(R.id.iv_play_pause, intent_paly);
                /* 下一个  按钮 */
                buttonIntent.putExtra(INTENT_BUTTONID_TAG, BUTTON_NEXT_ID);
                PendingIntent intent_next = PendingIntent.getBroadcast(getContext(), BUTTON_NEXT_ID, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                mRemoteViews.setOnClickPendingIntent(R.id.iv_next, intent_next);
                /* 关闭  按钮 */
                buttonIntent.putExtra(INTENT_BUTTONID_TAG, BUTTON_CLOSE_ID);
                PendingIntent intent_close = PendingIntent.getBroadcast(getContext(), BUTTON_CLOSE_ID, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                mRemoteViews.setOnClickPendingIntent(R.id.iv_close, intent_close);
            }

        }else{
            //如果版本号低于(3.0),那么不显示按钮
            mRemoteViews.setViewVisibility(R.id.iv_play_pause, View.GONE);
            mRemoteViews.setViewVisibility(R.id.iv_next, View.GONE);
            mRemoteViews.setViewVisibility(R.id.iv_close, View.GONE);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            if (isPlaying()) {
                mRemoteViews.setImageViewResource(R.id.iv_play_pause, R.mipmap.voice_play);
            } else {
                mRemoteViews.setImageViewResource(R.id.iv_play_pause, R.mipmap.voice_pause);
            }
            mRemoteViews.setTextViewText(R.id.tv_title, lesson.getTitleList().get(playIndex));
            mRemoteViews.setTextViewText(R.id.tv_name, lesson.getTeacher_name());
            mRemoteViews.setImageViewBitmap(R.id.iv_thumb, bitmap);
        }


        Intent intent = new Intent(getContext(), WelcomeActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 1, intent, PendingIntent.FLAG_ONE_SHOT);

        builder.setContent(mRemoteViews)
            .setContentIntent(pendingIntent)
            .setWhen(System.currentTimeMillis())// 通知产生的时间,会在通知信息里显示
            .setTicker("正在播放")
            .setPriority(Notification.PRIORITY_DEFAULT)// 设置该通知优先级
            .setOngoing(true)
            .setSmallIcon(R.drawable.logo);
        notification = builder.build();
        notification.flags = Notification.FLAG_ONGOING_EVENT;
        notificationManager.notify(NOTIFICATION_ID, notification);
    }

    /**
     * (通知栏中的点击事件是通过广播来通知的,所以在需要处理点击事件的地方注册广播即可)
     * 广播监听按钮点击事件
     */
    public class ButtonBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(ACTION_BUTTON)) {
                //通过传递过来的ID判断按钮点击属性或者通过getResultCode()获得相应点击事件
                int buttonId = intent.getIntExtra(INTENT_BUTTONID_TAG, 0);
                switch (buttonId) {
                    case BUTTON_PALY_ID:
                        onPlayOrPauseBtnClick();
                        break;
                    case BUTTON_NEXT_ID:
                        onNextBtnClick(true,1);
                        break;
                    case BUTTON_CLOSE_ID:
                        onCloseBtnClick();
                        break;
                    default:
                        break;
                }
            }
        }

    }

    /**
     * 开启或暂停
     */
    private void onPlayOrPauseBtnClick() {
        App.getMusicService().playOrPause();
        boolean isPlaying = isPlaying();
        if (isPlaying) {
            mRemoteViews.setImageViewResource(R.id.iv_play_pause, R.mipmap.voice_play);
        } else {
            mRemoteViews.setImageViewResource(R.id.iv_play_pause, R.mipmap.voice_pause);
        }
        notificationManager.notify(NOTIFICATION_ID, notification);
        //通知前端变更状态
        setPlayOrPauseGlobalEvent(isPlaying);
    }

    /**
     * 下一课
     * @param isStep
     * @param num
     */
    private void onNextBtnClick(boolean isStep,int num) {
        LessonInfo lesson = App.getLessonInfo();
        int playIndex = lesson.getIndex();
        if (isStep){
            playIndex += num;
        }else{
            playIndex = num;
        }
        if (playIndex < (lesson.getSectionidList().size())) {
            lesson.setIndex(playIndex);
            App.getMusicService().setVideoUrl(getContext(), lesson.getVideoUrlList().get(playIndex));
            App.getMusicService().start();
            setNogification();
            //通知前端变更状态
            setPreOrNextGlobalEvent(playIndex);
        }
    }

    /**
     * 关闭音频
     */
    public void onCloseBtnClick() {
        App.getMusicService().stop();
        App.setLessonInfo(null);
        /**
         * 关闭通知
         */
        if (receiver != null) {
            getContext().unregisterReceiver(receiver);
            receiver = null;
        }
        if (notificationManager != null) {
            notificationManager.cancel(NOTIFICATION_ID);
        }

        //通知前端变更状态
        setCloseVoiceGlobalEvent();
    }

    public void initService() {
        if (App.getMusicService() == null) {
            App.setMusicService(new MusicService());
            bindServiceConnection();
        }
    }

    /**
     * 前台-开始播放
     *
     * @param
     */
    @JSMethod(uiThread = true)
    public void play(Map data) {
        if (data != null && data.size() > 0) {

            int id = Integer.valueOf(data.get("id").toString());
            String thumb = data.get("thumb").toString();
            String teacherName = data.get("teacher_name").toString();
            int playIndex = Integer.valueOf(data.get("index").toString());

            String[] titleArr = data.get("titlestr").toString().split(",");
            String[] sectionidArr = data.get("sectionidstr").toString().split(",");
            String[] videourlArr = data.get("videourlstr").toString().split(",");

            String videoUrl = videourlArr[playIndex];

            if (!TextUtils.isEmpty(videoUrl)) {
                initService();
                App.getMusicService().setVideoUrl(getContext(), videoUrl);
                App.getMusicService().start();

                LessonInfo lessonInfo = new LessonInfo();
                lessonInfo.setId(id);
                lessonInfo.setThumb(thumb);
                lessonInfo.setTeacher_name(teacherName);
                lessonInfo.setIndex(playIndex);
                lessonInfo.setSectionidList(Arrays.asList(sectionidArr));
                lessonInfo.setTitleList(Arrays.asList(titleArr));
                lessonInfo.setVideoUrlList(Arrays.asList(videourlArr));
                App.setLessonInfo(lessonInfo);

                setNogification();
            }
        }

    }

    /**
     * 前台-开始/暂停播放
     *
     * @param
     */
    @JSMethod(uiThread = true)
    public void playOrPause() {
        onPlayOrPauseBtnClick();
    }

    /**
     * 前台-上一课或下一课
     *
     * @param
     */
    @JSMethod(uiThread = true)
    public void preOrNext(int index) {
        if (index>=0) {
            onNextBtnClick(false,index);
        }
    }

    /**
     * 停止播放
     *
     * @param
     */
    @JSMethod(uiThread = true)
    public void stop() {
        onCloseBtnClick();
    }

    /**
     * 判断是否正在播放,及最新播放的课程信息
     *
     * @param callback
     */
    @JSMethod(uiThread = false)
    public void checkLesson(JSCallback callback) {
        boolean isPlaying = isPlaying();

        Map<String, Object> map = new HashMap<>();
        map.put("isPlaying", isPlaying);
        map.put("lessonInfo", App.getLessonInfo());
        //int flag = isPlaying?1:0;
        callback.invokeAndKeepAlive(map);
    }

    //添加监听事件通知前端
    public void setPlayOrPauseGlobalEvent(boolean isPlaying){
        Map<String,Object> params=new HashMap<>();
        params.put("playStaus",isPlaying?"1":"0");
        List<WXSDKInstance> instances = WXSDKManager.getInstance().getWXRenderManager().getAllInstances();
        for (WXSDKInstance instance : instances) {
            instance.fireGlobalEventCallback("playOrPauseGlobalEvent",params);
        }

    }
    public void setPreOrNextGlobalEvent(int playIndex){
        Map<String,Object> params=new HashMap<>();
        params.put("playIndex",playIndex);
        //在weex端切换了页面后,直接使用wXSDKInstance是无法操作回调事件的,用以下方法解决
        List<WXSDKInstance> instances = WXSDKManager.getInstance().getWXRenderManager().getAllInstances();
        for (WXSDKInstance instance : instances) {
            instance.fireGlobalEventCallback("preOrNextGlobalEvent",params);
        }
    }

    public void setCloseVoiceGlobalEvent(){
        List<WXSDKInstance> instances = WXSDKManager.getInstance().getWXRenderManager().getAllInstances();
        for (WXSDKInstance instance : instances) {
            instance.fireGlobalEventCallback("CloseVoiceGlobalEvent",null);
        }
    }

}
通知栏自定义样式
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="58dp"
    >

    <ImageView
        android:id="@+id/iv_thumb"
        android:layout_width="64dp"
        android:layout_height="58dp"
        android:src="@drawable/logo"/>

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_weight="1">
        <TextView
            android:id="@+id/tv_title"
            android:layout_marginTop="8dp"
            android:text="著名情感专家绛妖精:10节婚姻必修课,跟上幸福的脚步"
            android:lines="1"
            android:textSize="14sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_name"
            android:text="某某专家"
            android:textSize="12sp"
            android:lines="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="8dp"/>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="18dp">
        <ImageView
            android:id="@+id/iv_play_pause"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/voice_play"
            android:layout_marginRight="20dp"/>
        <ImageView
            android:id="@+id/iv_next"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/voice_next"
            android:layout_marginRight="20dp"/>
        <ImageView
            android:id="@+id/iv_close"
            android:layout_width="18dp"
            android:layout_height="18dp"
            android:src="@mipmap/voice_close"
            android:layout_marginTop="4dp"/>
    </LinearLayout>
</LinearLayout>

 四.AndroidManifest.xml添加service

<service android:name=".service.MusicService" android:exported="true"></service>

五.weex前端核心代码

1.在create中添加监听事件

 //监听事件
var globalEvent = weex.requireModule('globalEvent');
	//播放或暂停,当切换了页面,以下监听失去了效果
	globalEvent.addEventListener("playOrPauseGlobalEvent", function (e) {
	console.log("playOrPauseGlobalEvent:",e)
	self.playing = e.playStaus == "1";
});
//上一课或下一课
globalEvent.addEventListener("preOrNextGlobalEvent", function (e) {
	console.log("preOrNextGlobalEvent:",e)
	if(e.playIndex>=0){
	    self.playing = true;
	    self.currentSectionIndex = e.playIndex;
	}
});
//关闭
globalEvent.addEventListener("CloseVoiceGlobalEvent", function (e) {
	console.log("CloseVoiceGlobalEvent:",e)
	self.playing = false;
	self.isClose = true;
});

2.播放功能

startLearn(){
	var lessonInfo = {
	    id:this.id,
	    teacher_name:this.lessonInfo.teacher,
	    thumb:this.lessonInfo.images,
	    index:this.currentSectionIndex,
	    titlestr:this.titleArr.join(','),
	    sectionidstr:this.sectionidArr.join(','),
	    videourlstr:this.videourlArr.join(','),
	}
	console.log(lessonInfo)
	this.playing = true;
	weex.requireModule('MusicModule').play(lessonInfo);
	
}

3.暂停与开始

playOrPause(){
	if(this.id!=0){
	    //this.playing = !this.playing;
	    if(this.isClose){
		if(this.lessonInfo.section_list>0){
		    this.checkIsPlaying();
		}
	    }else{
		weex.requireModule('MusicModule').playOrPause();
	    }

	}
}

4.上/下一章节

preOrNext(step){
	if(!this.isClose) {
	    let self = this;
	    let index = this.currentSectionIndex + step;
	    var len = this.lessonInfo.section_list.length;
	    console.log("index", index)
	    if (index >= 0 && index < len) {
		self.playing = false;
		weex.requireModule('MusicModule').preOrNext(index);
	    } else {
		this.$notice.toast({message: '没有更多课程了'});
	    }
	}
}

5.当从其他页面跳转播放页面,页面加载完成时调用

checkIsPlaying(){
	var _this = this;
	weex.requireModule('MusicModule').checkLesson(function (ret) {
	    console.log('checkIsPlaying--',ret)
	    console.log('currentSectionIndex->0--',_this.currentSectionIndex)
	    if(!ret.isPlaying){
		_this.startLearn();
	    }else{

		if(typeof(ret.lessonInfo) != "undefined"){
		    //如果正在播放的与现在的不是同一课程,则切换到现在这个
		    if(ret.lessonInfo.id!=_this.id){
			_this.startLearn();
		    }else{
			//同个课程不同章节
			if(parseInt(_this.currentSectionIndex) != parseInt(ret.lessonInfo.index)){
			    _this.playing = false;
			    weex.requireModule('MusicModule').preOrNext(_this.currentSectionIndex);
			}
		    }
		    console.log('currentSectionIndex->1--',_this.currentSectionIndex)
		    _this.playing = true;
		}
	    }
	});
}

 

待完成功能

1.播放时间及进度条

2.封装为component组件或插件形式方便调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值