不少人都在詢問如何實作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" />
圖片示範
Here i have coming error,
回覆刪除"ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
at NgForOf.ngOnChanges (common.js:2570)
at checkAndUpdateDirectiveInline (core.js:12365)
at checkAndUpdateNodeInline (core.js:13893)
at checkAndUpdateNode (core.js:13836)
at debugCheckAndUpdateNode (core.js:14729)
at debugCheckDirectivesFn (core.js:14670)
at Object.eval [as updateDirectives] (HomePage.html:14)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:14655)
at checkAndUpdateView (core.js:13802)
at callViewAction (core.js:14153)"
作者已經移除這則留言。
回覆刪除想詢問一下最近實作參考此文章用cordova與WebRTC , 完全教學文章內容一樣
回覆刪除在打包Ionic cordova build android 會現錯誤訊息
angularfire2 與 firebase 當時開發版本是多少??
用最新版本會出錯 , 但是降本又錯其他訊息 ,一直無解
是否可以再次更新一下內容?
{
刪除"name": "ionicwebRTC",
"version": "0.0.1",
"author": "Ionic Framework",
"homepage": "http://ionicframework.com/",
"private": true,
"scripts": {
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"lint": "ionic-app-scripts lint",
"ionic:build": "ionic-app-scripts build",
"ionic:serve": "ionic-app-scripts serve"
},
"dependencies": {
"@angular/common": "4.1.3",
"@angular/compiler": "4.1.3",
"@angular/compiler-cli": "4.1.3",
"@angular/core": "4.1.3",
"@angular/forms": "4.1.3",
"@angular/http": "4.1.3",
"@angular/platform-browser": "4.1.3",
"@angular/platform-browser-dynamic": "4.1.3",
"@ionic-native/core": "3.12.1",
"@ionic-native/splash-screen": "3.12.1",
"@ionic-native/status-bar": "3.12.1",
"@ionic/storage": "2.0.1",
"angular": "^1.3.0",
"angularfire": "^2.3.0",
"angularfire2": "^4.0.0-rc.2",
"autoprefixer": "^7.1.4",
"body-parser": "^1.18.2",
"clean-css": "^4.1.9",
"cordova-android": "^6.2.3",
"cordova-browser": "^4.1.0",
"cordova-plugin-device": "^1.1.4",
"cordova-plugin-splashscreen": "^4.0.3",
"cordova-plugin-statusbar": "^2.2.2",
"cordova-plugin-webrtc": "^0.1.1",
"cordova-plugin-whitelist": "^1.3.1",
"cors": "^2.8.4",
"express": "^4.15.5",
"firebase": "^4.4.0",
"ionic-angular": "3.6.1",
"ionic-plugin-keyboard": "^2.2.1",
"ionicons": "3.0.0",
"magic-string": "^0.22.4",
"node-sass": "^4.5.3",
"postcss": "^6.0.12",
"promise-polyfill": "6.0.2",
"proxy-middleware": "^0.15.0",
"rollup": "^0.50.0",
"rollup-pluginutils": "^2.0.1",
"rxjs": "5.4.0",
"start": "^5.1.0",
"sw-toolbox": "3.6.0",
"tiny-lr": "^1.0.5",
"tslint": "^5.7.0",
"webpack": "^3.6.0",
"ws": "^3.2.0",
"zone.js": "0.8.12"
},
"devDependencies": {
"@ionic/app-scripts": "^2.1.4",
"fs-extra": "^4.0.2",
"object-keys": "^0.2.0",
"typescript": "2.3.4"
},
"description": "An Ionic project",
"cordova": {
"plugins": {
"cordova-plugin-webrtc": {},
"cordova-plugin-device": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-whitelist": {},
"ionic-plugin-keyboard": {}
},
"platforms": [
"android",
"browser"
]
}
}