不少人都在詢問如何實作cordova的WebRTC,目前作者使用Peer.JS 就能完成一連串的影像互傳的功能,此篇文章在『Angular2 簡易版的webRTC』已簡單介紹過了,目前要更進一步實作出Cordova 在手機上與電腦也能互傳影像。
一、介紹FireBase
支援real-time的一種雲端服務,更重要的一點是完全免費的喔!!!
簡單的key-value的JSON格式,支援資料庫的匯入和匯出,順帶一提免費版的有些容量是有限制的。
為何需要雲端資料庫FireBase儲存資料,因為Peer.js 會產生一組perid讓對方可以透過perid 互傳影像,所以儲存登入者名稱和peerid…
Google 登入à go to console à新增專案
點選overview旁邊的設定à專案設定
選擇 firebase 加入網路應用程式
複製以下的設定檔
一、建立ionic 專案
ionic start myApp tabs
$ ionic cordova plugin add cordova-plugin-firebase
$ npm install --save @ionic-native/firebase
$ npm install angularfire2 firebase --save
Providers/databaseservice/user.ts
(實作資料層)
import { Injectable } from '@angular/core';
import {AngularFireDatabase,FirebaseListObservable } from 'angularfire2/database';
@Injectable()
export class UserService {
constructor(private _af: AngularFireDatabase) {
}
public listUsers(): FirebaseListObservable<any[]>{
return this._af.list('users');
}
public addUser(userName,peerID){
this.listUsers().push({ userName: userName, peerID: peerID});
}
public removeUser(userName){
let removeItem = this._af.list('users', {
query: {
orderByChild: "userName",
equalTo: userName
}
});
// Query the
list for the purposes of this example:
removeItem.subscribe((items) => {
// Remove
the matching item:
if (items.length) {
removeItem.remove(items[0].$key)
.then(() => console.log('removed ' + items[0].$key))
.catch((error) => console.log(error));
}
});
}
}
修改app.module.ts
import { AngularFireModule } from 'angularfire2';
import {AngularFireDatabaseModule} from 'angularfire2/database';
import { UserService } from "../providers/databaseservice/users";
// AF2 Settings
export const firebaseConfig = {
apiKey: "xxxxxxxxxx",
authDomain: "xxxxxxxxx.firebaseapp.com",
databaseURL: "https://
xxxxxxxxx.firebaseio.com",
storageBucket: "xxxxxxxxx.appspot.com",
messagingSenderId: "xxxxxxxxx"
};
注入module
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
AngularFireModule.initializeApp(firebaseConfig),
AngularFireDatabaseModule
],
注入prvider
providers: [
StatusBar,
SplashScreen,
UserService,
{provide: ErrorHandler, useClass: IonicErrorHandler},
]
ionic g page login 建立登入頁
pages/login/login.html
<ion-header>
<ion-navbar color="primary">
<ion-title align-title="center">登錄</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-item>
<ion-label fixed>名稱</ion-label>
<ion-input type="text" [(ngModel)]="name"></ion-input>
</ion-item>
<ion-item>
<ion-label fixed>密碼</ion-label>
<ion-input type="text" [(ngModel)]="password"></ion-input>
</ion-item>
<p>
<button ion-button full round (click)="login(name)">登錄</button>
</ion-content>
pages/login/login.ts
@Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
constructor(public navCtrl: NavController, public navParams: NavParams) {
}
login(name) {
登入頁面並傳入參數
this.navCtrl.push(TabsPage, {
userName: name
});
}
}
pages/tabs/tabs.ts
import { Component } from '@angular/core';
import { HomePage } from '../home/home';
import { NavController,NavParams } from 'ionic-angular';
@Component({
templateUrl: 'tabs.html'
})
export class TabsPage {
userName; 宣告參數
tab1Root = HomePage;
constructor(params: NavParams) {
this.userName = params.get("userName"); 取得參數
}
}
pages/home/home.html
<ion-header>
<ion-navbar>
<ion-title>{{viewUserName}}
歡迎</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h1>{{mypeerid}}</h1>
<ion-card>
<ion-card-content>
<video #myvideo></video>
</ion-card-content>
</ion-card>
<ion-item *ngFor="let
user of users | async"
item="item" (click)="startCall(user.userName,user.peerID)">
{{user.userName}} - {{user.$key}}</ion-item>
<button ion-button full (click)="videoconnect()">開始通話</button>
<button ion-button full (click)="stopCall(viewUserName)">結束通話</button>
</ion-content>
pages/home/home.ts
import { Component, ViewChild, OnInit } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { FirebaseListObservable } from 'angularfire2/database'; 注入fireBase的相關模組
import { UserService } from "../../providers/databaseservice/users";
declare var Peer: any; 宣告peer的物件
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage implements OnInit {
title = 'app';
mypeerid: any;
peer;
anotherid;
key;
@ViewChild('myvideo') myVideo: any; 取得myVideo的元素
users: FirebaseListObservable<any[]> fireBase的陣列集合
viewUserName:any;
_streamCopy;
constructor(public navCtrl: NavController, public navParams: NavParams, public userService: UserService) {
this.users = userService.listUsers(); 取得資料users的集合
this.viewUserName=navParams.data;
}
ngOnInit() {
let video = this.myVideo.nativeElement;
this.peer = new Peer({ host: 'peerjs-server.herokuapp.com', secure: true, port: 443 })
this.mypeerid = this.peer.id;
setTimeout(() => {
this.mypeerid = this.peer.id;
this.userService.addUser(this.viewUserName,this.peer.id );
}, 1000);
this.peer.on('connection', function (conn) {
conn.on('data', function (data) {
console.log(data);
});
});
var n = <any>navigator;
n.getUserMedia = (n.getUserMedia || n.webkitGetUserMedia || n.mozGetUserMedia || n.msGetUserMedia);
this.peer.on('call', function (call) {
n.getUserMedia({ video: true, audio: false }, function (stream) {
call.answer(stream);
call.on('stream', function (remotestream) {
video.src = URL.createObjectURL(remotestream);
video.play();
})
}, function (err) {
console.log('Failed to
get stream', err);
})
})
}
startCall(userName,anotherID) {
this.anotherid = anotherID;
var conn = this.peer.connect(anotherID);
conn.on('open', function () {
conn.send('Message
from that id');
});
}
this.peer.on('disconnected', function () {
console.log("disconnected");
});
videoconnect(){
let video = this.myVideo.nativeElement;
var localvar = this.peer;
var fname = this.anotherid;
var n = <any>navigator;
console.log("another
peerID:"+this.anotherid);
n.getUserMedia = ( n.getUserMedia || n.webkitGetUserMedia || n.mozGetUserMedia || n.msGetUserMedia );
n.getUserMedia({
video: { width: 700, height: 720 } , audio:false
}, function(stream) {
var call = localvar.call(fname, stream);
call.on('stream', function(remotestream) {
video.src = URL.createObjectURL(remotestream);
video.play();
})
}, function(err){
alert(err.name);
console.log('Failed to
get stream', err);
})
}
stopCall(userName) {
this.userService.removeUser(userName);
this.peer.destroy();
}
}
Ionic cordova
build android
設定Android的權限
Platforms/android/ AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
圖片示範