最近开发记录
程序要求:工厂内通讯使用,及时联络处理问题,收到消息及时提醒用户处理。目前已测试android4以上
1.保持程序后台运行
2.维持长连接,接收即时消息,后台播放无声音乐,每十秒执行一次,无声音乐长度为1秒
3.接收到信息,显示通知,提醒,语音播报
4.消息存储,根据不同的消息跳转不同的页面
需要用到插件
1.cordova-plugin-background-mode 后台运行
2.cordova-plugin-appminimize 程序最小化
3. 即时消息采用第三方融云
4. cordova-plugin-nativeaudio 播放本地音频
5.cordova-plugin-local-notification 本地消息通知
6.语音播报采用百度语音合成
7.cordova-sqlite-storage 存储消息
1.后台运行插件(ionic3版本,如果是ionic4,按照4的文档添加)
1.1 添加插件
$ ionic cordova plugin add cordova-sqlite-storage
$ npm install --save @ionic-native/sqlite@4
$ ionic cordova plugin add cordova-plugin-appminimize
$ npm install --save @ionic-native/app-minimize@4
1.2 插件添加到应用程序的模块中(此处不讲)
1.3 在app.component中启用(有删减)
import { Component, ViewChild } from '@angular/core';
import { Nav, Platform, App, Keyboard, IonicApp, Events } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { AppMinimize } from '@ionic-native/app-minimize';
import { BackgroundMode } from '@ionic-native/background-mode';
import { ToastServiceProvider } from '../providers/toast-service/toast-service';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = LoginPage;
backButtonPressed: boolean = false; //用于判断返回键是否触发
constructor(public platform: Platform,
public statusBar: StatusBar,
public splashScreen: SplashScreen,
private toast: ToastServiceProvider,
private appMinimize: AppMinimize,
private keyboard: Keyboard,
private ionicApp: IonicApp,
private app: App,
private events: Events,
private backgroundMode: BackgroundMode,
private helper: HelperProvider) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
// this.statusBar.styleDefault();
// this.splashScreen.hide();
//判断是否真机运行
if (this.helper.isMobile()) {
this.registerBackButtonAction();//注册返回按键事件
this.setBackground();//设置后台运行
}
this.statusBar.styleDefault();
this.splashScreen.hide();
this.nav.setRoot(LoginPage);
});
}
/**
* 设置后台运行
*/
setBackground() {
this.backgroundMode.enable();
//延迟启用
setTimeout(() => {
this.backgroundMode.setDefaults({
title: ‘正在后台运行,请勿关闭应用’,
text: ‘点击即可进入应用’,
icon: 'assets/imgs/logo.png'
})
}, 2000);
}
/**
* android 物理返回键处理
*/
registerBackButtonAction() {
this.platform.registerBackButtonAction(() => {
if (this.keyboard.isOpen()) {//如果键盘开启则隐藏键盘
this.keyboard.close();
return;
}
//如果想点击返回按钮隐藏toast或loading或Overlay就把下面加上
// this.ionicApp._toastPortal.getActive() || this.ionicApp._loadingPortal.getActive() || this.ionicApp._overlayPortal.getActive()
let activePortal = this.ionicApp._modalPortal.getActive();
if (activePortal) {
activePortal.dismiss().catch(() => { });
activePortal.onDidDismiss(() => { });
return;
}
let loadingPortal = this.ionicApp._loadingPortal.getActive();
if (loadingPortal) {
loadingPortal.dismiss().catch(() => { });
return;
}
if (this.app.getActiveNav().canGoBack() || this.nav.canGoBack()) {
this.app.navPop();
} else {
this.showExit();
}
return;
// return this.app.getActiveNav().canGoBack() ? this.app.navPop() : this.showExit();
}, 100);
}
//双击退出提示框
showExit() {
if (this.backButtonPressed) { //当触发标志为true时,即2秒内双击返回按键则退出APP
// this.platform.exitApp();
this.appMinimize.minimize();
} else {
this.toast.showToast('再次返回将自动切换到后台运行');
this.backButtonPressed = true;
setTimeout(() => this.backButtonPressed = false, 2000);//2秒内没有再次点击返回则将触发标志标记为false
}
}
}
关联文件ToastServiceProvider
import { Injectable } from '@angular/core';
import { ToastController } from 'ionic-angular';
/*
Generated class for the ToastServiceProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class ToastServiceProvider {
toast: any;//Toast
constructor(private toastCtrl: ToastController) {
}
/**
* 吐司提示(默认中间)
*/
showToast(mes: string, position?: string) {
if (this.toast) {
this.toast.dismiss();
}
this.toast = this.toastCtrl.create({
message: mes,
duration: 2000,
position: position ? position : 'middle'
});
this.toast.present();
}
}
HelperProvider
import { Injectable } from '@angular/core';
import { Platform,} from 'ionic-angular';
import { Network } from '@ionic-native/network';;
/*
Generated class for the HelperProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class HelperProvider {
constructor(private platform: Platform,
private network: Network) {
}
/**
* 是否真机环境
* @return {boolean}
*/
isMobile(): boolean {
return this.platform.is('mobile') && !this.platform.is('mobileweb');
}
/**
* 是否android真机环境
* @return {boolean}
*/
isAndroid(): boolean {
return this.isMobile() && this.platform.is('android');
}
/**
* 是否android6以下
*/
isAndroidLow():boolean{
return this.isAndroid() && this.platform.version().major < 6;
}
/**
* 是否ios真机环境
* @return {boolean}
*/
isIos(): boolean {
return this.isMobile() && (this.platform.is('ios') || this.platform.is('ipad') || this.platform.is('iphone'));
}
/**
* 获取网络类型 如`unknown`, `ethernet`, `wifi`, `2g`, `3g`, `4g`, `cellular`, `none`
*/
getNetworkType(): string {
if (!this.isMobile()) {
return 'wifi';
}
return this.network.type;
}
/**
* 判断是否有网络
* @returns {boolean}
*/
isConnecting(): boolean {
if (this.getNetworkType() == 'none') {
//没有网络
}
return this.getNetworkType() != 'none';
}
/**
* 获取随机数
*/
generateMixed(n: number) {
let res = "";
var chars = ['2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];//随机数
for (var i = 0; i < n; i++) {
var id = Math.ceil(Math.random() * 31);
res += chars[id];
}
return res;
}
}
2 集成融云
由于测试期间使用融云web SDK在android6以下出现连接融云服务器受限,出现403状态码,最后为了解决该问题,暂时在android6以下版本采用融云cordova插件代替
2.1 添加融云cordova插件
融云cordova地址
$ ionic cordova plugin add cordova-plugin-rongcloud-im
2.2 添加web版融云
融云web文档地址
2.3 在app.component中
///
如图:
2.4 创建RongcloudServieProvider
$ ionic g provider RongcloudServie
2.5 修改RongcloudServieProvider
StorageServiceProvider参考
SqliteServiceProvider 参考
import { HelperProvider } from './../helper/helper';
import { Injectable } from '@angular/core';
import { Events } from 'ionic-angular';
import { StorageServiceProvider } from '../../providers/storage-service/storage-service';
import { SqliteServiceProvider } from '../../providers/sqlite-service/sqlite-service';
declare let RongCloudLibPlugin;
/*
Generated class for the RongcloudServieProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class RongcloudServieProvider {
IM_KEY = 'xxxxxxxxxxxxxxxxx';//融云官网申请的应用key
constructor(public events: Events,
private sqlite: SqliteServiceProvider,
private storageService: StorageServiceProvider,
private helper: HelperProvider) {
}
/**
* 注册实例化RongYunIm服务
* Ming 2018-10-29
* @memberof RongcloudServieProvider
*/
init() {
if (this.helper.isAndroidLow()) {
RongCloudLibPlugin.init({ appKey: IM_KEY },(ret, err)=>{
// alert(ret.status);
});
} else {
RongIMLib.RongIMClient.init(IM_KEY);
}
}
/**
* 链接融云服务器状态回掉事件
* Ming 2018-10-29
* @param
* @memberof RongcloudServieProvider
*/
connectionStatusListener() {
if (this.helper.isAndroidLow()) {
RongCloudLibPlugin.setConnectionStatusListener((ret, err)=>{
this.onListenerStatus(ret.result.connectionStatus);
});
} else {
RongIMLib.RongIMClient.setConnectionStatusListener({
onChanged: (status) => {
this.onListenerStatus(status);
}
});
}
}
onListenerStatus(status) {
switch (status) {
case RongIMLib.ConnectionStatus.CONNECTED:
// this.coms.closeLoading(loading);
console.log('聊天服务链接成功');
break;
case RongIMLib.ConnectionStatus.CONNECTING:
// this.coms.toastInfo("正在链接聊天服务", 1000, 'top');
break;
// case RongIMLib.ConnectionStatus.DISCONNECTED:
case RongIMLib.ConnectionStatus.NETWORK_UNAVAILABLE:
// this.coms.toastError('服务已经断开 正为您重新连接');
this.reconnect();
// alert(moment());
break;
case RongIMLib.ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT:
// this.logoutAndClear();
// this.coms.toastInfo("其他设备登录成功,您已经被迫下线!", 2000, 'top');
// this.alertService.showAlert('你已在其他设备登录成功,可能导致此设备无法正常接收信息');
// this.reconnect();
break;
case RongIMLib.ConnectionStatus.DOMAIN_INCORRECT:
this.alertService.showAlert('域名解析失败');
this.reconnect();
// this.coms.toastError("域名解析失败", 2000, 'top');
break;
case RongIMLib.ConnectionStatus.DISCONNECTED:
// this.alertService.showAlert('已断开连接');
this.reconnect();
// this.coms.toastError("域名解析失败", 2000, 'top');
break;
case RongIMLib.ConnectionStatus.CONNECTION_CLOSED:
// this.alertService.showAlert('连接已关闭');
// this.reconnect();
this.connect(this.globalData.rongcloudtoken);
// this.coms.toastError("域名解析失败", 2000, 'top');
break;
}
}
/**
* 收到消息的监听回掉事件
* Ming 2018-10-29
* @param
* @memberof RongcloudServieProvider
*/
async receiveMessageListener() {
if (this.helper.isAndroidLow()) {
RongCloudLibPlugin.setOnReceiveMessageListener((ret, err) => {
this.onReceived(ret.result.message);
})
} else {
RongIMLib.RongIMClient.setOnReceiveMessageListener({
// 接收到的消息
onReceived: (message) => {
this.onReceived(message)
}
})
}
}
/**
* 处理消息 (根据自己实际需求处理)
* @param message
*/
async onReceived(message) {
if (message && message.content.extra) {
let msg = JSON.parse(message.content.extra);
if (msg) {
//保存数据
this.sqlite.executeSql('INSERT INTO message(userId,title, state, content, sendId, sendTime, msgType, isWarning, referenceId, receivers,isValid,isDeleted,createTime,referenceType,referenceCode) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
[this.globalData.userId.toString(), msg.title.toString(), '0', msg.content ? msg.content.toString() : '', msg.sendId.toString(), msg.sendTime.toString(), msg.msgType.toString(), msg.isWarning, msg.referenceId ? msg.referenceId.toString() : '', JSON.stringify(msg.receivers), msg.isValid, msg.isDeleted, new Date().getTime().toString(), msg.referenceType ? msg.referenceType.toString() : '',msg.referenceCode?msg.referenceCode.toString():""]).then(() => {
this.events.publish('message:new', msg);//广播通知有信息
});
}
}
/**
* 获取未读消息
* 此接口必须在init()方法之后,连接融云服务器 connect 之前调用。
* Ming 2018-10-29
* @param {*} token 传入链接的Token
* @param {(hasMessage) => {}} successCallback 执行成功后的回掉事件
* @param {(err) => {}} errorCallback 执行错误后的回掉事件
* @memberof RongcloudServieProvider
*/
hasRemoteUnreadMessages(token): Promise {
return new Promise((resolve, reject) => {
RongIMLib.RongIMClient.getInstance().hasRemoteUnreadMessages(token, {
onSuccess: (hasMessage) => {
resolve(hasMessage)
console.log('未读消息' + hasMessage)
},
onError: (err) => {
reject(err)
}
});
})
}
// 获取未读消息总数
getUnreadMessageNumber(): Promise {
return new Promise((resolve, reject) => {
RongIMLib.RongIMClient.getInstance().getTotalUnreadCount({
onSuccess: (count) => {
resolve(count);
},
onError: (error) => {
reject(error)
}
});
})
}
/**
* 发送信息
*/
sendMessage(conversationtype: RongIMLib.ConversationType, targetId: string, msg: any): Promise {
return new Promise((resolve, reject) => {
if(this.helper.isAndroidLow()){
RongCloudLibPlugin.sendTextMessage({
conversationType: conversationtype,
targetId: targetId,
text: msg
},(ret, err)=>{
resolve(ret);
})
} else {
RongIMLib.RongIMClient.getInstance().sendMessage(
conversationtype,
targetId,
msg,
{
onSuccess: (message) => {
resolve(message);
},
onError: (errorCode) => {
let info = '';
switch (errorCode) {
case RongIMLib.ErrorCode.TIMEOUT:
info = '超时';
break;
case RongIMLib.ErrorCode.REJECTED_BY_BLACKLIST:
info = '在黑名单中,无法向对方发送消息';
break;
case RongIMLib.ErrorCode.NOT_IN_DISCUSSION:
info = '不在讨论组中';
break;
case RongIMLib.ErrorCode.NOT_IN_GROUP:
info = '不在群组中';
break;
case RongIMLib.ErrorCode.NOT_IN_CHATROOM:
info = '不在聊天室中';
break;
default:
info = 'x';
break;
}
reject(info)
},
onBefore: (messageId) => {
reject(messageId)
}
}
);
}
})
}
/**
* 通过融云返回的TokenId链接融云服务器
* 传入链接的Token
* @param {*} token
* @param {(userId) => {}} successCallback 执行成功后的回掉事件并得到用户UserId
* @param {() => {}} tokenIncorrectCallback Token失效事件
* @param {(errorCode) => {}} errorCallback 执行错误后的回掉事件并放回错误编码
* @memberof RongcloudServieProvider
*/
connect(token): Promise {
return new Promise((resolve, reject) => {
if (this.helper.isAndroidLow()) {
RongCloudLibPlugin.connect({
token: token
},(ret, err)=>{
if (ret.status == 'success') {
// alert(ret.result.userId);
resolve(ret.result.userId);
} else {
resolve(ret);
}
})
} else {
RongIMLib.RongIMClient.connect(token, {
onSuccess: (userId) => {
resolve(userId);
// this.setHeartbeat();//开启心跳
},
onTokenIncorrect: () => {
reject('token无效');
},
onError: (errorCode) => {
let info = '';
switch (errorCode) {
case RongIMLib.ErrorCode.TIMEOUT:
info = '超时';
break;
case RongIMLib.ConnectionState.IDENTIFIER_REJECTED:
info = 'appkey不正确';
break;
case RongIMLib.ConnectionState.SERVER_UNAVAILABLE:
info = '服务器不可用';
break;
}
reject(info)
}
})
}
})
}
getCurrentConnectionStatus() {
if (this.helper.isAndroidLow()) {
return RongCloudLibPlugin.getConnectionStatus();
} else {
return RongIMLib.RongIMClient.getInstance().getCurrentConnectionStatus();
}
}
/**
* 融云重新连接
*/
reconnect(): Promise {
if (this.storageService.sessionRead('rongcloud') == 'yes') {
// this.loadingService.showLoading('正在重新连接聊天服务器');
return new Promise((resolve, reject) => {
if (this.helper.isAndroidLow()) {
this.connect(this.globalData.rongcloudtoken);
} else {
RongIMLib.RongIMClient.reconnect({
onSuccess: (userId) => {
// this.loadingService.hideLoading();
// console.log("融云重连成功." + userId);
resolve(userId);
},
onTokenIncorrect: () => {
// console.log('token无效');
// this.loadingService.hideLoading();
reject('token无效');
this.alertService.showAlert('融云重连失败token无效');
},
onError: (errorCode) => {
// console.log("融云重连失败" + errorCode);
// this.loadingService.hideLoading();
reject(errorCode);
// this.alertService.showAlert('融云重连失败' + errorCode);
}
}, {
auto: true,
url: 'cdn.ronghub.com/RongIMLib-2.3.2.min.js',
rate: [100, 1000, 3000, 6000, 10000]
});
}
})
}
}
/**
* 断开融云连接
*/
disconnectRy() {
if (this.helper.isAndroidLow()) {
// 描述:断开后是否接收 Push
RongCloudLibPlugin.disconnect({ isReceivePush: false },(ret, err)=>{
// alert(ret.status);
});
} else {
RongIMLib.RongIMClient.getInstance().disconnect();
}
}
/**
* 登出融云
*/
logoutRy() {
try {
if (this.helper.isAndroidLow()) {
RongCloudLibPlugin.logout((ret, err)=>{
// alert(ret.status);
});
} else {
RongIMLib.RongIMClient.getInstance().logout();
}
} catch (e) {
console.log(e)
}
}
}
2.6 在app.component中调用及监听,修改app.component为
import { Component, ViewChild } from '@angular/core';
import { Nav, Platform, App, Keyboard, IonicApp, Events } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { AppMinimize } from '@ionic-native/app-minimize';
import { BackgroundMode } from '@ionic-native/background-mode';
import { ToastServiceProvider } from '../providers/toast-service/toast-service';
import { RongcloudServieProvider } from '../providers/rongcloud-servie/rongcloud-servie';
import { SqliteServiceProvider } from '../providers/sqlite-service/sqlite-service';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = LoginPage;
backButtonPressed: boolean = false; //用于判断返回键是否触发
constructor(public platform: Platform,
public statusBar: StatusBar,
public splashScreen: SplashScreen,
private toast: ToastServiceProvider,
private appMinimize: AppMinimize,
private keyboard: Keyboard,
private ionicApp: IonicApp,
private app: App,
private events: Events,
private backgroundMode: BackgroundMode,
private rongService: RongcloudServieProvider,
private sqlite: SqliteServiceProvider,
private helper: HelperProvider) {
this.initializeApp();
}
initializeApp() {
//监听登录成功 登录成功或失败都需要触发一个event事件
this.events.subscribe('login:success', (res) => {
//登录成功拿到后台返回的用户对应的token
this.connectRongCloud(res.token);
});
//监听用户退出登录
this.events.subscribe('login:out', () => {
this.onExit();
})
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
// this.statusBar.styleDefault();
// this.splashScreen.hide();
//初始化融云
this.rongService.init();
//判断是否真机运行
if (this.helper.isMobile()) {
this.registerBackButtonAction();//注册返回按键事件
this.setBackground();//设置后台运行
}
//确保异步执行完后才隐藏启动动画
this.events.subscribe('db:create', () => {
//创建数据库与表成功后才关闭动画跳转页面
this.statusBar.styleDefault();
this.splashScreen.hide();
this.nav.setRoot(LoginPage);
})
//初始化创建数据库
this.sqlite.createDb();
});
}
/**
* 设置后台运行
*/
setBackground() {
this.backgroundMode.enable();
//延迟启用
setTimeout(() => {
this.backgroundMode.setDefaults({
title: ‘正在后台运行,请勿关闭应用’,
text: ‘点击即可进入应用’,
icon: 'assets/imgs/logo.png'
})
}, 2000);
}
/**
* android 物理返回键处理
*/
registerBackButtonAction() {
this.platform.registerBackButtonAction(() => {
if (this.keyboard.isOpen()) {//如果键盘开启则隐藏键盘
this.keyboard.close();
return;
}
//如果想点击返回按钮隐藏toast或loading或Overlay就把下面加上
// this.ionicApp._toastPortal.getActive() || this.ionicApp._loadingPortal.getActive() || this.ionicApp._overlayPortal.getActive()
let activePortal = this.ionicApp._modalPortal.getActive();
if (activePortal) {
activePortal.dismiss().catch(() => { });
activePortal.onDidDismiss(() => { });
return;
}
let loadingPortal = this.ionicApp._loadingPortal.getActive();
if (loadingPortal) {
loadingPortal.dismiss().catch(() => { });
return;
}
if (this.app.getActiveNav().canGoBack() || this.nav.canGoBack()) {
this.app.navPop();
} else {
this.showExit();
}
return;
// return this.app.getActiveNav().canGoBack() ? this.app.navPop() : this.showExit();
}, 100);
}
//双击退出提示框
showExit() {
if (this.backButtonPressed) { //当触发标志为true时,即2秒内双击返回按键则退出APP
// this.platform.exitApp();
this.appMinimize.minimize();
} else {
this.toast.showToast('再次返回将自动切换到后台运行');
this.backButtonPressed = true;
setTimeout(() => this.backButtonPressed = false, 2000);//2秒内没有再次点击返回则将触发标志标记为false
}
}
/**
* 连接融云
*/
connectRongCloud(token) {
this.events.subscribe('message:new', message => {
if (this.helper.isMobile()) {
// 如果后台运行,则把程序从后台切换到前台运行
this.backgroundMode.moveToForeground();
}
});
this.rongService.connectionStatusListener();
// 监听融云的服务...
this.rongService.receiveMessageListener();
this.rongService.connect(token).then((userId) => {
// 成功连接融云服务
console.log('登录成功:' + userId);
}).catch((error) => {
// 登录失败处理
this.toast.showToast('登录聊天服务器失败' + error);
})
}
}
/**
* 退出登录,清除用户登录信息
*/
onExit() {
this.rongService.logoutRy();
this.nav.setRoot(LoginPage);
}
3 添加播放音频与本地通知
3.1 添加插件
$ ionic cordova plugin add cordova-plugin-nativeaudio
$ npm install --save @ionic-native/native-audio@4
$ ionic cordova plugin add cordova-plugin-local-notification
$ npm install --save @ionic-native/local-notifications@4
3.2 插件添加到应用程序的模块中、
3.3 创建AudioServiceProvider
$ ionic g provider AudioService
3.4 修改AudioServiceProvider
import { StorageServiceProvider } from './../storage-service/storage-service';
import { HelperProvider } from './../helper/helper';
import { Injectable } from '@angular/core';
import { NativeAudio } from '@ionic-native/native-audio';
/*
Generated class for the AudioServiceProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class AudioServiceProvider {
time:any;
audio: HTMLAudioElement;
constructor(private nativeAudio: NativeAudio,
private helper: HelperProvider,
private storageService: StorageServiceProvider) {
// this.nativeAudio.preloadComplex('bell', 'assets/bell.mp3', 1, 1, 0).catch(e => console.log(e));
//缓存无声音频
this.nativeAudio.preloadComplex('no', 'assets/no.mp3', 1, 1, 0).catch(e => console.log(e));
// this.nativeAudio.preloadComplex('prompt', 'assets/prompt.mp3', 1, 1, 0).catch(e => console.log(e));
//添加收到消息提示声音,为了兼容低版本vivo和web端
this.audio = document.createElement('audio');
this.audio.src = 'http://xxx/assets/file/prompt.mp3';
this.audio.autoplay = false;
}
/**
* 播放无声音音乐
*/
backgroundPlay() {
if(this.time){
clearInterval(this.time);
}
this.time = setInterval(()=>{
setTimeout(() => {
try{
this.nativeAudio.play('no');
}catch(err){
console.log(err)
}
}, 9000);
},10000)
}
/**
* 停止播放背景音乐
*/
stopBackground(){
clearInterval(this.time);
this.time = null;
this.nativeAudio.stop('no');
}
/**
* 播放消息提示声音
*/
playMsg(){
// this.nativeAudio.play('prompt');
this.audio.play();
}
}
3.5 修改app.component,追加代码
import { AudioServiceProvider } from '../providers/audio-service/audio-service';
import { LocalNotifications } from '@ionic-native/local-notifications';
constructor(private audioService: AudioServiceProvider,
private localNotifications: LocalNotifications) {}
/**
* 设置后台运行
*/
setBackground() {
this.audioService.backgroundPlay();
}
/**
* 连接融云
*/
connectRongCloud() {
this.events.subscribe('message:new', message => {
// 播放消息声音
this.audioService.playMsg();
if (this.helper.isMobile()) {
//显示通知
this.localNotifications.schedule({
id: message.id,
icon: 'res://ic_chat',
smallIcon: 'res://ic_chat',
sound: null,
silent: true,
title:message.title,
text: message.content,
data: message
});
//监听点击事件
this.localNotifications.on('click').subscribe(res => {
//清除所有消息
this.localNotifications.clearAll();
});
}
});
}
4 集成百度语音合成
一开始采用cordova-plugin-tts进行播报,设置语言为中文,但在vivo手机出现只读英文,中文被过滤无法播报,好像是编码问题,后来选用百度语音合成,因为免费
4.1 创建应用
点击注册并创建应用
成功后会得到AppID,API Key,Secret Key
4.2 Java后台设置
文档链接
后台写一个接口代码,播放参数前端传给后台
/**
* 测试单聊
*
* @param tex
* @return
* @throws Exception
*/
@RequestMapping("getAudio")
public void getAudio(HttpServletRequest request, Model model,
@RequestParam("lan") String lan,
@RequestParam("ctp") Integer ctp,
@RequestParam("tex") String tex,
@RequestParam("cuid") String cuid,
@RequestParam("spd") String spd,
@RequestParam("pit") String pit,
@RequestParam("vol") String vol,
@RequestParam("per") String per,
HttpServletResponse response
) throws Exception {
HashMap option = new HashMap<>();
option.put("cuid", cuid);
option.put("spd", spd);
option.put("pit", pit);
option.put("vol", vol);
option.put("per", per);
byte[] buff = ttsUtils.textToSpeech(tex, lan, ctp, option);
if (buff != null) {
response.setContentType("audio/mp3");
OutputStream outputStream = response.getOutputStream();
outputStream.write(buff);
outputStream.close();
}
}
4.3 创建TtsServiceProvider
$ ionic g provider TtsService
填写代码
import { StorageServiceProvider } from './../storage-service/storage-service';
import { Injectable } from '@angular/core';
import { ConfigProvider } from '../config/config';
/*
Generated class for the TtsServiceProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class TtsServiceProvider {
audio: any;
options = {
lan: "zh",//语言
ctp: '1',
cuid: '',//唯一标识
tex: '',//播放内容
spd: 5,//语速,取值0-15,默认为5中语速
pit: 5,//音调,取值0-15,默认为5中语调
vol: 15,//音量,取值0-15,默认为5中音量
per: 0//发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
}
constructor( private storageService: StorageServiceProvider) {
}
/**
* 初始化百度tts
*/
init() {
this.audio = document.createElement('audio');
this.audio.autoplay = false;
//如果第一次启动,参数不存在,则存储默认参数
if (!this.storageService.read("baiduTTS")) {
this.storageService.write("baiduTTS", this.options);
}
}
/**
* 播放内容
* @param text
*/
speak(text: string) {
//读取最新存储语音设置
this.options = this.storageService.read("baiduTTS");
this.options.cuid = 'xxx';//此处应为用户唯一标识
//url编码
this.options.tex = encodeURIComponent(text);
//设置地址为后台播放地址
this.audio.src = 'http://xxx/message/getAudio' + '?' + this.toBodyString(this.options);
this.audio.play();
}
}
/**
* 停止播放
*/
stop() {
this.audio.pause();
}
/**
*
* @param obj
* @return {string}
* 声明: var obj= {};
* 调用: toQueryString(obj);
* 返回: "name=%E5%B0%8F%E5%86%9B&age=23"
*/
toBodyString(obj) {
let ret = [];
for (let key in obj) {
if (key != 'constructor') {
key = encodeURIComponent(key);
let values = obj[key];
if (values && values.constructor == Array) {//数组
let queryValues = [];
for (let i = 0, len = values.length, value; i < len; i++) {
value = values[i];
queryValues.push(this.toQueryPair(key, value));
}
ret = ret.concat(queryValues);
} else { //字符串
ret.push(this.toQueryPair(key, values));
}
}
}
return ret.join('&');
}
private toQueryPair(key, value) {
if (typeof value == 'undefined') {
return key;
}
return key + '=' + encodeURIComponent(value === null ? '' : String(value));
}
}
4.4 修改app.component,追加代码
import { TtsServiceProvider } from '../providers/tts-service/tts-service';
constructor(private ttsService: TtsServiceProvider) {}
initializeApp() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
// 初始化百度tts
this.ttsService.init();
});
}
/**
* 连接融云
*/
connectRongCloud() {
this.events.subscribe('message:new', message => {
// 播放文本
this.ttsService.speak( message.content);
if (this.helper.isMobile()) {
this.localNotifications.on('click').subscribe(res => {
//清除该条
this.audioService.stopPlay();
//停止播放
this.ttsService.stop();
this.localNotifications.clearAll();
});
}
});
}