I'd like to implement Huawei Ads into a Huawei HTML5 QuickApp. I've got the Quick App running.
How do I implement a Huawei Ads Banner Ad into it, please?
QuickApp do not support banner ads,only support native ads and incentive ads.
The HTML5 QuickApp access ad needs to use the two-way communication with the framework of the web component of the QuickApp to obtain the ad.
The following is an example code for connecting an HTML5 QuickApp to an ad.
<template>
<div class="doc-page">
<web class="web-page" src="{{webUrl}}" trustedurl="{{list}}" onpagestart="onPageStart"
useragent="default"
onmessage="onMessage"
fullscreendirection="{{fullscreenDirection}}"
jumppolicy="{{linkJumpPolicy}}"
multiwindow="{{openMultiwindow}}"
onpagefinish="onPageFinish"
ontitlereceive="onTitleReceive"
onerror="onError"
id="web"
allowthirdpartycookies="{{allowThirdPartyCookies}}">
</web>
</div>
</template>
<style>
.doc-page {
flex-direction: column;
flex-direction: column;
justify-content: center;
align-content: center;
align-items: center;
}
.web-page {
width: 100%;
height: 100%;
}
</style>
<script>
import router from "#system.router"
import prompt from '#system.prompt'
import ad from "#service.ad"
let nativeAd
let rewardedVideoAd
export default {
props: ['websrc'],
data: {
native: {
adUnitId: 'testu7m3hc4gvm',
adData: {},
errStr: '',
},
rewarded: {
adUnitId: 'testx9dtjwj8hp',
isShow: 'false',
errStr: ''
},
title: "",
// TODO Replace the link to the H5 url
webUrl: "http://xxx/h5_ad_demo.html",
allowThirdPartyCookies: true,
fullscreenDirection: "landscape",
linkJumpPolicy: "default",
openMultiwindow: false,
list: ["new RegExp('https?.*')"],
},
onPageStart(e) {
console.info('pagestart: ' + e.url)
},
// Each page switch triggers
onPageFinish(e) {
console.info('pagefinish: ' + e.url, e.canBack, e.canForward)
},
onTitleReceive(e) {
this.title = e.title;
},
onError(e) {
console.info('pageError : ' + e.errorMsg)
},
onMessage(e) {
console.info('onmessage e = ' + e.message + ", url = " + e.url);
prompt.showToast({
message: e.message + ': ' + e.url
})
var msg=e.message;
if(msg==='requestNativeAd'){
if(this.isSupportAd()){
this.requestNativeAd();
}
}else if(msg==='requestRewardAd'){
if(this.isSupportAd()){
this.requestRewardedAd();
}
}else if(msg==='reqReportNativeAdShow'){
this.reportNativeShow();
}else if(msg==='reqReportNativeAdClick'){
this.reportNativeClick();
}
},
isSupportAd:function(){
let provider = ad.getProvider();
if(provider==='huawei'){
return true;
}
return false ;
},
requestNativeAd() {
console.info("requestNativeAd");
nativeAd = ad.createNativeAd({ adUnitId: this.native.adUnitId })
nativeAd.onLoad((data) => {
console.info('nativeAd data loaded: ' + JSON.stringify(data));
this.native.adData = data.adList[0];
if (this.native.adData) {
let nativeAdObj={"nativeAdData":data};
let nativeAdMsg=JSON.stringify(nativeAdObj);
console.info("requestNativeAd onload nativeAdMsg= "+nativeAdMsg);
let senddata={"message":nativeAdMsg};
this.$element('web').postMessage(senddata);
}
})
nativeAd.onError((e) => {
console.error('load ad error:' + JSON.stringify(e));
let nativeAdErrorObj={"nativeAdDataError":e};
let nativeAdErrorMsg=JSON.stringify(nativeAdErrorObj);
console.info("requestNativeAd onError nativeAdErrorMsg= "+nativeAdErrorMsg);
let errordata={"message":nativeAdErrorMsg};
this.$element('web').postMessage(errordata);
})
nativeAd.load()
},
reportNativeShow() {
nativeAd.reportAdShow({ 'adId': this.native.adData.adId })
},
reportNativeClick() {
nativeAd.reportAdClick({ 'adId': this.native.adData.adId })
},
requestRewardedAd() {
rewardedVideoAd = ad.createRewardedVideoAd({ adUnitId: this.rewarded.adUnitId });
/**Set the callback function for successful advertisement loading and invoke the ad show method to display the advertisement. */
rewardedVideoAd.onLoad(() => {
console.info("rewarded video ad onLoad");
rewardedVideoAd.show();
})
rewardedVideoAd.offLoad(() => {
console.info("rewarded video ad offLoad");
})
/**Listen to the video ad error event. */
rewardedVideoAd.onError((e) => {
console.error('load rewarded video ad error:' + JSON.stringify(e));
this.rewarded.errStr = JSON.stringify(e)
})
/**Listening for the event of disabling the incentive video ad */
rewardedVideoAd.onClose(() => {
console.info("rewarded video ad onClose");
})
rewardedVideoAd.load();
},
onDestroy() {
nativeAd && nativeAd.destroy()
rewardedVideoAd && rewardedVideoAd.destroy()
},
isCanForward() {
this.$element('web').canForward({
callback: function (e) {
if (e) {
this.$element('web').forward();
}
}.bind(this)
})
},
isCanBack() {
this.$element('web').canBack({
callback: function (e) {
if (e) {
this.$element('web').back();
} else {
router.back();
}
}.bind(this)
})
},
onShow: function () {
console.info(" onshow");
},
onHide: function () {
console.info(" onHide");
},
onBackPress() {
this.isCanBack();
return true
},
}
</script>
h5_ad_demo.html
<html>
<head>
<title>ad Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
table.dataintable {
margin-top:10px;
border-collapse:collapse;
border:1px solid #aaa;
width:100%;
}
table.dataintable th {
vertical-align:baseline;
padding:5px 15px 5px 6px;
background-color:#d5d5d5;
border:1px solid #aaa;
text-align:left;
}
table.dataintable td {
vertical-align:text-top;
padding:6px 15px 6px 6px;
background-color:#efefef;
border:1px solid #aaa;
}
</style>
<script language="javascript">
system.onmessage = function(data) {
console.info("onmessage data="+data);
setResult(data);
var adDataObject=JSON.parse(data);
if(adDataObject.nativeAdData){
var nativeAdList=adDataObject.nativeAdData.adList[0];
if(nativeAdList){
if (nativeAdList.imgUrlList) {
var imgSrc=nativeAdList.imgUrlList[0];
document.getElementById("adImage").src= imgSrc;
console.info('ad data adImgSrc: ' +imgSrc);
}
}
}
}
function reportNativeShow() {
system.postMessage("reqReportNativeAdShow");
}
function reportNativeAdClick() {
console.info("reportNativeAdClick");
system.postMessage("reqReportNativeAdClick");
}
function getNativeAd(){
system.postMessage("requestNativeAd");
}
function getRewardAd(){
system.postMessage("requestRewardAd");
}
function setResult(str) {
document.getElementById("nativeAdDataResult").innerHTML= str
}
function setResultnew(str) {
document.getElementById("resultnew").innerHTML= str
}
function onLoadSuc(){
console.info("onLoadSuc");
reportNativeShow();
}
function openNewWeb(){
system.go("https://www.huawei.com")
}
function openNewWindow(){
window.open("http://www.w3school.com.cn")
}
</script>
</head>
<body>
<p>
H5 ad demo
</p>
<p>
ResultNativeAd: <br/> <span id="nativeAdDataResult" style="height:100px;">(unknown)</span>
</p>
<p>
ResultRewardAd: <br/> <span id="resultnew" style="height:100px;">(unknown)</span>
</p>
<hr style="height:3px;border:none;border-top:3px double red;" />
<p><button onclick="getNativeAd()">Native Ad</button></p>
<hr style="height:3px;border:none;border-top:3px double red;" />
<p><button onclick="getRewardAd()">Reward Ad</button></p>
<hr style="height:3px;border:none;border-top:3px double red;" />
<p>
<img src="/i/eg_tulip.jpg" id="adImage" alt="test ad" onclick="reportNativeAdClick()" onload="onLoadSuc()"/>
<hr style="height:3px;border:none;border-top:3px double red;" />
</p>
</body>
</html>
For more details, pls kindly refer the following link:
Web component
Accessing HUAWEI Ads Publisher Service
Related
Im injecting html and js in my web view. What im trying to do is allow support on my Android phone to connect to a local Node.js Server to send and receive Audio and Video.
This is my Server.js that runs:
const HTTPS_PORT = 8443;
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
// Yes, TLS is required
const serverConfig = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
};
// ----------------------------------------------------------------------------------------
// Create a server for the client html page
const handleRequest = function(request, response) {
// Render the single client html file for any request the HTTP server receives
console.log('request received: ' + request.url);
if(request.url === '/') {
response.writeHead(200, {'Content-Type': 'text/html'});
response.end(fs.readFileSync('client/index.html'));
} else if(request.url === '/webrtc.js') {
response.writeHead(200, {'Content-Type': 'application/javascript'});
response.end(fs.readFileSync('client/webrtc.js'));
}
};
const httpsServer = https.createServer(serverConfig, handleRequest);
httpsServer.listen(HTTPS_PORT, '192.168.1.62');
// ----------------------------------------------------------------------------------------
// Create a server for handling websocket calls
const wss = new WebSocketServer({server: httpsServer});
wss.on('connection', function(ws) {
ws.on('message', function(message) {
// Broadcast any received message to all clients
console.log('received: %s', message);
wss.broadcast(message);
});
});
wss.broadcast = function(data) {
this.clients.forEach(function(client) {
if(client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
console.log('Server running. Visit https://localhost:' + HTTPS_PORT + ' in Firefox/Chrome.\n\n\
Some important notes:\n\
* Note the HTTPS; there is no HTTP -> HTTPS redirect.\n\
* You\'ll also need to accept the invalid TLS certificate.\n\
* Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines.\n'
);
This is the HTML thats viewable on the Webview in Android:
<!DOCTYPE html>
<html lang="en">
<head>
<title>P2P Video Chat</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=320, initial-scale=1" />
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<style>
div::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
}
#live {
background-color: #000;
height:100%;
width:100%;
}
#local-video {
width: 100%;
background-color:black;
}
#divider{
height:20px;
background-color:black;
}
#remote-video {
width: 100%;
background-color:black;
}
#end-call {
position: absolute;
top: 0;
left: 0;
padding: 8px;
background-color: red;
color: white;
border: none;
}
.d1{border-bottom:1px solid #ffffff;font-weight:bold;font-size:22px;color:#90CAF9;top:20px;left:20px;padding:8px;background-color:#0D47A1;opacity:0.7;text-align:center;}
.s1{color:white;font-size:12px;}
.d2{position:absolute;left:20px;top:20px;width:70px;height:70px;border-radius:35px;background-color:green;opacity:0.7;display:flex:justify-content:center;align-items:center;}
.i1{width:50px;height:50px;margin-left:10px;margin-top:10px;}
#record1{display:none;left:20px;border-radius:25px;width:50px;height:50px;position:absolute;background-color:red;opacity:0.7;padding:8px;color:white;font-weight:bold;font-size:18px;margin-top:-180px;z-index:400;}
#timer1{width:100%;margin-top:-50px;position:absolute;text-align:center;color:white;padding:8px;z-index:800;font-size:10px;}
.d3{position:absolute;opacity:0.7;padding:0px;color:white;font-weight:bold;font-size:18px;margin-top:-105px;display:inline-block;z-index:1000}
.d4{font-weight:bold;margin-top:-15px;margin-left:15px;position:absolute;width:120px;height:30px;z-index:300;}
.i2{float:left;width:50px;height:50px;margin-top:3px;}
.d5{float:left;color:black;margin-top:0px;margin-left:5px;}
.d6{position:absolute;color:gray;font-size:23px;text-align:center;z-index:200;width:100%;margin-top:-22px;padding:0px;background-color:white;}
.d7{background-color:white;padding:10px;border-radius:25px;font-size:23px;}
.d8{position:absolute;opacity:0.7;padding:0px;color:white;font-weight:bold;font-size:18px;margin-top:70px;display:inline-block;z-index:400;}
#timer2{width:100%;margin-top:80px;position:absolute;text-align:center;color:white;padding:8px;z-index:800;font-size:3px;}
#record2{display:none;left:20px;border-radius:25px;width:50px;height:50px;position:absolute;background-color:red;opacity:0.7;padding:8px;color:white;font-weight:bold;font-size:18px;margin-top:135px;z-index:100}
.d9{position:absolute;left:20px;bottom:20px;width:70px;height:70px;border-radius:35px;background-color:green;z-index:1200;opacity:0.7;display:flex:justify-content:center;align-items:center;}
.i3{width:50px;height:50px;margin-left:10px;margin-top:10px;}
.d10{border-top:1px solid #ffffff;text-align:center;font-weight:bold;font-size:22px;color:#90CAF9;position:absolute;left:0;bottom:0;right:0;padding:8px;background-color:#0D47A1;opacity:0.7;}
.s2{color:white;font-size:12px;}
/* Exact resolution */
#media (-webkit-device-pixel-ratio: 1) {
}
/* Minimum resolution */
#media (-webkit-min-device-pixel-ratio: 1.1) {
.d1{font-size:8px;}
.d2{width:40px;height:40px;background-color:red;}
.d2 img{width:20px;height:20px}
#record1{width:20px;height:20px;border-radius:10px; margin-top:-100px;}
#timer1{font-size:8px;}
#record2{width:20px;height:20px;border-radius:10px;margin-top:53px;}
#timer2{font-size:8px;margin-top:15px;}
.d3{font-size:12px;display:inline-block;}
.d5{font-size:8px;margin-top:4px;}
.d6{font-size:23px;}
.d8{font-size:12px;margin-top:50px;display:inline-block;}
.d3 img{ width:20px; height:20px;margin-right:5px; padding:2px;display:inline-block;}
.d8 img{ width:20px; height:20px;margin-right:5px;padding:2px;display:inline-block;}
.i2{float:left;width:20px;height:20px;}
.d9{width:40px;height:40px;background-color:red;}
.d9 img{width:20px;height:20px;}
.i4{width:20px;height:20px;margin-right:5px;}
.i5{width:20px;height:20px;margin-right:5px;}
.d7{font-size:10px;}
.d10{font-size:8px;}
.d11{display:inline-block;margin-top:16px;position:absolute;width:300px;font-size:8px;}
.d12{display:inline-block;margin-top:16px;position:absolute;width:300px;font-size:8px;}
}
/* Maximum resolution */
#media (-webkit-max-device-pixel-ratio: 3) {
}
</style>
</head>
<body style="margin:0;padding:0;overflow:hidden;" leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">
<!-- App code -->
<div id="live">
<div class=""><div class="d1"><img class="i4" src="vote.png" />VOTE: <span class="s1">123</span></div></div>
<div class="d2"><img class="i1" src="like.png" /></div>
<video id="remote-video" autoplay muted="true"></video>
<div id="divider">
<div id="record1" class=""></div>
<div id="timer1" class="">15 seconds</div>
<div class="d3"><img class="i1" src="rap.png" /><div class="d11">MC Trix</div></div>
<div class="d4">
<img class="i2" src="views.png"/> <div class="d5">1.1k</div> </div>
<div class="d6"><div class="d7">VS</div></div>
<div class="d8"><img class="i1" src="rap.png" /><div class="d12">MC Trix and Metz</div></div>
<div id="timer2" class="">15 seconds</div>
<div id="record2" class=""></div>
</div>
<video id="local-video" muted="true" autoplay></video>
<input value="lfnvsfnsnfvsnvsn" style="z-index:10000;position:absolute;top:0;left:0;" type="button" onclick="start(true)" />
<div class="d9"><img class="i3" src="like.png" /></div>
<div class=""><div class="d10"><img class="i5" src="vote.png" />VOTE: <span class="s2">123</span></div></div>
<!--<button id="end-call" onclick="endCall()">End Call</button>-->
</div>
</body>
</html>
<script>
var timer = 15;
setTimeout(setTimer1, 5000);
var interval;
function setTimer1(){
interval = setInterval(setTimer1Elapsed, 1000);
}
function setTimer1Elapsed(){
--timer;
if(timer > 0){
$("#timer1").text(timer + " seconds");
}else{
$("#record1").fadeTo(100, 0.3, function() { $(this).fadeTo(500, 1.0); });
$("#remote-video")[0].muted = !$("#remote-video")[0].muted;
$("#timer1").text("");
interval = null;
}
}
var timer2 = 15;
var interval2;
//function setTimer2AfterContestantFinish(){
setTimeout(setTimer2, 5000);
//}
function setTimer2(){
interval2 = setInterval(setTimer1Elapsed2, 1000);
}
function setTimer1Elapsed2(){
if(timer2 > 0){
$("#timer2").text(timer2 + " seconds");
}else{
$("#record2").fadeTo(100, 0.3, function() { $(this).fadeTo(500, 1.0); });
$("#local-video")[0].muted = !$("#local-video")[0].muted;
$("#timer2").text("");
interval = null;
}
--timer2;
}
var height = $(document).height() / 2 - 60;
$("#remote-video").height(height);
$("#local-video").height(height);
$("#remote-video").css("opacity", 0);
$("#local-video").css("opacity", 0);
$("#live").width($(document).width());
$("#live").height($(document).height());
var localVideo;
var localStream;
var remoteVideo;
var peerConnection;
var uuid;
var serverConnection;
var peerConnectionConfig = {
'iceServers': [
{'urls': 'stun:stun.stunprotocol.org:3478'},
{'urls': 'stun:stun.l.google.com:19302'},
]
};
pageReady();
async function pageReady() {
uuid = createUUID();
localVideo = document.getElementById('local-video');
remoteVideo = document.getElementById('remote-video');
serverConnection = new WebSocket('wss://' + "192.168.1.62" + ':8443');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: false,
};
var stream;
if(navigator.mediaDevices.getUserMedia) {
stream = await navigator.mediaDevices.getUserMedia(constraints).catch(errorHandler);
getUserMediaSuccess(stream);
} else {
alert('Your browser does not support getUserMedia API');
}
}
function getUserMediaSuccess(stream) {
alert(uuid);
$("#local-video").css("opacity", 1);
localStream = stream;
localVideo.srcObject = stream;
localVideo.play();
}
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function gotIceCandidate(event) {
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate, 'uuid': uuid}));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function() {
serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler);
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.srcObject = event.streams[0];
}
function errorHandler(error) {
console.log("xxxxx " + error);
}
// Taken from http://stackoverflow.com/a/105074/515584
// Strictly speaking, it's not a real UUID, but it gets the job done here
function createUUID() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
</script>
I have the local video loading, just when the start(true) is causing the error:
WebSocket is already in CLOSING or CLOSED state.
Since most of the react-native-recaptchaV3 libraries are outdated, im trying to create component to get invisible recaptchaV3. But onMessage() returns nothing to get token. Can anyone help me to get this done?
when i remove androidLayerType="software" app got crashed. if i use androidLayerType="software" i got undefined in console.
"react-native-webview": "^11.17.2",
class ReCaptchaComponent extends React.Component {
_webViewRef = React.createRef();
constructor(props) {
super(props);
}
render() {
return (
<View style={{flex: 0.0001, width: 0, height: 0}}>
<WebView
ref={ref => {
this._webViewRef = ref;
}}
androidLayerType="software"
javaScriptEnabled
originWhitelist={['*']}
automaticallyAdjustContentInsets
mixedContentMode={'always'}
onMessage={(e: any) => { console.log('onReceiveToken',e.nativeEvent.data);
}}
source={{html: recaptchaHtml,baseUrl: 'https://testing.xyz'}}
/>
</View>
);
}
}
const recaptchaHtml = `<!DOCTYPE html>
<html>
<head>
<style>
body {
display: flex;
justify-content: left;
align-items: top;
}
</style>
</head>
<body>
<div id="inline-badge"></div>
<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onRecaptchaLoadCallback"></script>
<script>
function onRecaptchaLoadCallback() {
var clientId = grecaptcha.render('inline-badge', {
'sitekey': '_xBu49Sf-rsc1',
'badge': 'inline',
'size': 'invisible'
});
grecaptcha.ready(function () {
grecaptcha.execute(clientId, {
action: 'verify'
})
.then(function (token) {
window.ReactNativeWebView.postMessage(token, '*')
});
});
}
</script>
</body>
</html>`;
export default ReCaptchaComponent;
I have added
react-native-webview -> android -> src -> java -> RNCWebViewManager.java
on onReceivedSslError method i have changed,
handler.cancel()
To
handler.proceed();
I'm having real trouble trying to figure out why my code runs easily on both web and ios but shows a blank div on Android without any errors.
I'm using Ionic Angular and I've already triple checked Api keys.
My guess is that it has something to do with shadow-root but I failed in every attempt to fix it.
I'd be super gratefull for any insight I might be missing, Thanks in advance!
HTML:
<ion-content fullscreen class="mapContent">
<ion-grid class="container mapContent">
<ion-row class="mapContent">
<div #map id="map" class="map"></div>
</ion-row>
</ion-grid>
</ion-content>
TS:
#ViewChild('map') mapElement: ElementRef;
map: any;
constructor(
private geolocation: Geolocation,
) {}
ionViewDidEnter() {
this.loadGoogleMaps();
}
loadGoogleMaps(){
window['mapInit'] = () => {
this.initMap();
}
let script = document.createElement("script");
script.id = "googleMaps";
script.src = 'http://maps.google.com/maps/api/js?key=' + this.apiKey + '&callback=mapInit';
document.body.appendChild(script);
}
initMap(){
this.mapInitialised = true;
this.geolocation.getCurrentPosition().then((position) => {
let latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
let mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
this.map.addListener("click", (e) => {
this.placeMarker(e.latLng, this.map);
});
});
}
CSS:
ion-content.mapContent {
--background: transparent !important;
}
ion-grid.mapContent {
--background: transparent !important;
}
ion-row.mapContent {
--background: transparent !important;
}
.map {
margin: 10px 5px 20px;
border-radius: 20px;
width: 100%;
height: 200px;
}
I want to create a Group chat application based on Android and socket.io functionality just like Whatsapp.
I guess I don't really understand the question, but here is a very small simple chat room I wrote with socket.io a couple of years ago. I hope you can use it as a skeleton..
<body><ul id="Messages"></ul>
<form action="">
<input id="Message" autocomplete="off">
<input type="button" id="Send" value="Send">
</form>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$.getScript('socket.io/socket.io.js', function () {
initSocket();
});
var initSocket = function () {
var socket = io();
$('#Send').click(function () {
var userNameTag = $('#UserNameTag');
var nameTag = userNameTag.html();
if (nameTag) {
socket.emit('ioChatMessage', { text: nameTag + ': ' + $('#Message').val(), style: userNameTag[0].style });
} else {
socket.emit('ioChatMessage', { text: $('#Message').val() });
}
$('#Message').val('');
return false;
});
socket.on('ioChatMessage', function (msg) {
$('#Messages').append($('<li>').text(msg.text).css(msg.style));
});
window.onbeforeunload = function () {
socket.disconnect();
};
};
</script>
</body>
App.js
var app = require('express')();
var http = require('http').Server(app);
var socket = require('socket.io')(http);
app.get('*', function(req, res){
res.sendFile(__dirname + '/index.html');
});
socket.on('connection', function (io) {
io.on('ioChatMessage', function (msg) {
socket.emit('ioChatMessage', msg);
});
});
http.listen(process.env.PORT);
In this page you can learn how to build a chat group using socket.io in a browser:
https://socket.io/get-started/chat/
My recomendation if you want it to be an Android app is to do it like you see in the tutorial and then use Apache Cordova to make it an Android App anyone can install.
You can download it from here:
https://cordova.apache.org/
The final index.html should look like this:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
#messages { margin-bottom: 40px }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
window.scrollTo(0, document.body.scrollHeight);
});
});
</script>
</body>
</html>
And the index.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(port, function(){
console.log('listening on *:' + port);
});
The application runs fine on first launch, I can switch views and display ng-dialogues(i am using named ui-views),
After one or two suspensions or re-launches it still respond fine, and I can still scroll and type in inputs.
But it refuses to switch to other view or display an ng-dialogue. This issues goes away after force stopping the app.
I have tried to switch launch mode in config.xml to singleInstance and singleTask with no success. The problem is also present in release build.
Is doubt that my code causing this because it runs once right? Any idea?
Here is a sample code for the angular route main controller and index.html.
route
(function() {
"use strict";
angular
.module("cvideo")
.config(routeConfig);
/** #ngInject */
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state("home", {
url: "/",
views: {
nav: {
templateUrl: "app/components/navbar/navbar.html",
controller: "NavCtrl"
},
content: {
templateUrl: "app/main/main.html",
controller: "MainCtrl"
}
}
})
.state("jobs", {
url: "/jobs",
views: {
nav: {
templateUrl: "app/components/navbar/navbar.html",
controller: "NavCtrl"
},
content: {
templateUrl: "app/components/job/newJob.html",
controller: "JobCtrl"
}
}
});
$urlRouterProvider.otherwise("/");
}
})();
index.html
<body>
<div ui-view="nav"></div>
<div class="content" ui-view="content"></div>
</body>
MainCtrl
(function(){
"use strict";
angular.module("cvideo")
.controller("MainCtrl", function ($scope, ngDialog) {
$scope.jobs = [];
for (var i = 1; i < 10; i++) {
var job = {
title: "Job Offer " + Math.round(Math.random()*1000),
date: new Date(100*60 * 60 * 24 * 365*50*i),
description: "Job Offer "+i+" Description.",
qualification: "Job Offer " + i + " Required Qulifications.",
video: {
limit: i*10,
local: "",
web: ""
}
};
$scope.jobs.push(job);
}
$scope.preview = function (job) {
$scope.job = job;
ngDialog.open({
template: "app/components/job/job.html",
scope: $scope,
showClose:false
});
};
});
})();
main.html
<div class="jumbotron col-md-4" ng-repeat-start="job in jobs">
<div class="container">
<div class="row" ng-click="preview(job)">
<h3 ng-bind="job.title"></h3>
<label ng-bind="job.date|date:'Due MM/dd/yyyy'"></label>
<p ng-bind="job.description.length>100?job.description.substr(0,97)+'...':job.description"></p>
<div class="clearfix" ng-if="$index%3==2"></div>
</div>
</div>
</div>
<div ng-repeat-end=""></div>