I am using WebRTC for video and audio and I want to support flipping the camera in a mobile device from front to back and vice versa.
Using the below code Safari iOS works great, but Android Chrome will throw the exception NotReadableError: Could not start video source.
I am also closing any previous track.
var constraints = {
audio: false,
video: {
"width": {
"ideal": 1280
},
"height": {
"ideal": 720
},
"facingMode": {
"exact": "environment"
},
},
}
const userMedia = await navigator.mediaDevices.getUserMedia(constraints) // Will throw - NotReadableError: Could not start video source
I also tried the constraints without width and height.
{
"audio": false,
"video": {
"facingMode": {
"exact": "environment"
}
}
}
Any ideas on how to debug further or try things out will be appreciated.
[Update]
Testing with Android Firefox browser works as expected!
Related
I am working on a nuxt project and I want to add it to Google Play, but it requires an apk output
so is there any solution to get the apk file from Nuxt?
I've already tried using android studio but it was unsuccessful
manifest.json:
{
"name": "my nuxt app",
"short_name": "my lovely nuxt app",
"description": "pwa to apk",
"icons": [
{
"src": "/logo.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/300.png",
"sizes": "384x384",
"type": "image/jpg"
},{
"src": "/512.jpg",
"sizes": "512x512",
"type": "image/jpg"
}
],
"start_url": "/?standalone=true",
"display": "standalone",
"background_color": "#222",
"theme_color": "#222",
"lang": "fa",
"prefer_related_applications": true
}
and I get this error when I want to install it:
for security your phone is set to block installation
TWA are a thing as you can read here: https://www.ateamsoftsolutions.com/what-are-pwa-and-twa/
Meanwhile, this is not the same as having an .apk which is something totally different from the Web platform as you can see here: https://fileinfo.com/extension/apk (none of the extensions are ones used on the Web)
This is a totally different bundle language and ecosystem. Hence, you cannot port a PWA into a Google Play app.
You'll need to learn ways to make a mobile app with either Capacitor (Quasar) can help or similar solutions.
Or use React Native, Flutter or even vanilla Kotlin (the latter being the closest one to the machine).
In addition to kissu's comment, I always use Nuxt.js for regular websites but Ionic/Vue with Capacitor for mobile apps, it works great, same ecosystem and a great UI components and CLI from Ionic. This is just a suggestion for something that works and it has a minimum learning curve.
after so many searches and thanks to #kissu for give me a hint about twa i found the solution:
1.first of all u need a service worker for your nuxt project and put it in the static folder
example:
/static/sw.js
and inside of sw.js:
const options = {"workboxURL":"https://cdn.jsdelivr.net/npm/workbox-cdn#5.1.4/workbox/workbox-sw.js","importScripts":[],"config":{"debug":false},"cacheOptions":{"cacheId":"online-actor-prod","directoryIndex":"/","revision":"c35hcbL1ctml"},"clientsClaim":true,"skipWaiting":true,"cleanupOutdatedCaches":true,"offlineAnalytics":false,"preCaching":[{"revision":"c35hcbL1ctml","url":"/"}],"runtimeCaching":[{"urlPattern":"/_nuxt/","handler":"CacheFirst","method":"GET","strategyPlugins":[]},{"urlPattern":"/","handler":"NetworkFirst","method":"GET","strategyPlugins":[]}],"offlinePage":null,"pagesURLPattern":"/","offlineStrategy":"NetworkFirst"}
importScripts(...[options.workboxURL, ...options.importScripts])
initWorkbox(workbox, options)
workboxExtensions(workbox, options)
precacheAssets(workbox, options)
cachingExtensions(workbox, options)
runtimeCaching(workbox, options)
offlinePage(workbox, options)
routingExtensions(workbox, options)
function getProp(obj, prop) {
return prop.split('.').reduce((p, c) => p[c], obj)
}
function initWorkbox(workbox, options) {
if (options.config) {
// Set workbox config
workbox.setConfig(options.config)
}
if (options.cacheNames) {
// Set workbox cache names
workbox.core.setCacheNameDetails(options.cacheNames)
}
if (options.clientsClaim) {
// Start controlling any existing clients as soon as it activates
workbox.core.clientsClaim()
}
if (options.skipWaiting) {
workbox.core.skipWaiting()
}
if (options.cleanupOutdatedCaches) {
workbox.precaching.cleanupOutdatedCaches()
}
if (options.offlineAnalytics) {
// Enable offline Google Analytics tracking
workbox.googleAnalytics.initialize()
}
}
function precacheAssets(workbox, options) {
if (options.preCaching.length) {
workbox.precaching.precacheAndRoute(options.preCaching, options.cacheOptions)
}
}
function runtimeCaching(workbox, options) {
const requestInterceptor = {
requestWillFetch({ request }) {
if (request.cache === 'only-if-cached' && request.mode === 'no-cors') {
return new Request(request.url, { ...request, cache: 'default', mode: 'no-cors' })
}
return request
},
fetchDidFail(ctx) {
ctx.error.message =
'[workbox] Network request for ' + ctx.request.url + ' threw an error: ' + ctx.error.message
console.error(ctx.error, 'Details:', ctx)
},
handlerDidError(ctx) {
ctx.error.message =
`[workbox] Network handler threw an error: ` + ctx.error.message
console.error(ctx.error, 'Details:', ctx)
return null
}
}
for (const entry of options.runtimeCaching) {
const urlPattern = new RegExp(entry.urlPattern)
const method = entry.method || 'GET'
const plugins = (entry.strategyPlugins || [])
.map(p => new (getProp(workbox, p.use))(...p.config))
plugins.unshift(requestInterceptor)
const strategyOptions = { ...entry.strategyOptions, plugins }
const strategy = new workbox.strategies[entry.handler](strategyOptions)
workbox.routing.registerRoute(urlPattern, strategy, method)
}
}
function offlinePage(workbox, options) {
if (options.offlinePage) {
// Register router handler for offlinePage
workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => {
const strategy = new workbox.strategies[options.offlineStrategy]
return strategy
.handle({ request, event })
.catch(() => caches.match(options.offlinePage))
})
}
}
function workboxExtensions(workbox, options) {
}
function cachingExtensions(workbox, options) {
}
function routingExtensions(workbox, options) {
}
2.you also need a manifest , for that put this code in your nuxt.config.js:
export default{
pwa: {
manifest: {
name: 'example name',
short_name: 'example',
lang: 'fa',
theme_color: '#222',
background_color: '#222',
start_url: `/`,
prefer_related_applications: true,
},
icon: {
fileName: 'logo.png'
},
},
}
3.now everything is ready to create your apk, now you can search for pwa to apk in google And use sites that offer these services:
ive already tried these sites and all working well:
gonative.io
or
pwabuilder.com
When I use following code in development enviroment, it works fine. However Sharing.isAvailableAsync() return false in standalone app.
if (!(await Sharing.isAvailableAsync())) {
alert(`Uh oh, sharing isn't available on your platform`);
return;
}
// console.log(getImageLocalAddress);
await Sharing.shareAsync(fileAddress, {
mimeType: "image/jpeg",
dialogTitle: "Share Your Result",
});
I feel like the docs at react-native-fcm are a bit of a mess and I am having a hard time figuring this out.
I currently have a production app and my android users are telling me they are not receiving notifications for events where they should be. So this is stressing me out a lot right now. On iOS everything seems fine.
In the react-native-fcm example app you can see the following:
//FCM.createNotificationChannel is mandatory for Android targeting >=8. Otherwise you won't see any notification
componentDidMount() {
FCM.createNotificationChannel({
id: 'default',
name: 'Default',
description: 'used for example',
priority: 'high'
})
}
Do I need to call FCM.createNotificationChannel()?? I mainly use remote notifications so is this relevant in any way?
Here is MY setup:
import FCM, {
FCMEvent,
NotificationType,
RemoteNotificationResult,
WillPresentNotificationResult,
} from 'react-native-fcm';
FCM.on(FCMEvent.Notification, async (notif) => {
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
FCM.presentLocalNotification({
id: "new_message", // (optional for instant notification)
title: notif.fcm.title, // as FCM payload
body: notif.fcm.body, // as FCM payload (required)
sound: "default", // as FCM payload
priority: "high", // as FCM payload
click_action: "com.myapp.MyCategory", // as FCM payload - this is used as category identifier on iOS.
badge: 10, // as FCM payload IOS only, set 0 to clear badges
number: 10, // Android only
ticker: "My Notification Ticker", // Android only
auto_cancel: true, // Android only (default true)
large_icon: "ic_launcher", // Android only
icon: "ic_launcher", // as FCM payload, you can relace this with custom icon you put in mipmap
color: "blue", // Android only
vibrate: 300, // Android only default: 300, no vibration if you pass 0
wake_screen: true, // Android only, wake up screen when notification arrives
group: "group", // Android only
picture: "https://google.png", // Android only bigPicture style
ongoing: false, // Android only
my_custom_data:'my_custom_field_value', // extra data you want to throw
lights: true, // Android only, LED blinking (default false)
});
if(Platform.OS ==='ios'){
//optional
//iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application.
//This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
//notif._notificationType is available for iOS platfrom
switch(notif._notificationType){
case NotificationType.Remote:
notif.finish(RemoteNotificationResult.NewData) //other types available: RemoteNotificationResult.NewData, RemoteNotificationResult.ResultFailed
break;
case NotificationType.NotificationResponse:
notif.finish();
break;
case NotificationType.WillPresent:
notif.finish(WillPresentNotificationResult.All) //other types available: WillPresentNotificationResult.None
break;
}
}
});
FCM.on(FCMEvent.RefreshToken, (token) => {
try {
const { currentUser } = firebase.auth();
let updates = {};
updates[`/allUsers/serviceUsers/${currentUser.uid}/userInfo/fcmToken`] = token;
return firebase.database().ref().update(updates).catch(err => console.log('fcm refresh error', err))
} catch (e) {
console.log('couldnt update fcm refresh token', e)
}
});
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
class App extends Component {
componentWillMount() {
let config = {configgg}
!firebase.apps.length ? firebase.initializeApp(config) : firebase.app();
FCM.requestPermissions();
}
render() {
return (
<Provider store={store}>
<Router/>
</Provider>
);
}
}
export default App;
I mainly use remote notifications and it is critical for my app for it to work. Is there anything I am missing in my setup?
Any hint or suggestions will help me out a lot! Thanks!
EDIT:
Found this in adb logcat when receiving a notification (that did not show up)
NotificationService: No Channel found for pkg=com.lisdoworker, channelId=null, id=0, tag=GCM-Notification:9015992, opPkg=com.lisdoworker, callingUid=10487, userId=0, incomingUserId=0, notificationUid=10487, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
Does this have to do with FCM.createNotificationChannel()??
Yeah, apparently createNotificationChannel was added in version 16 to support Android 8 and it is barely documented.
We have videojs in places and we have DRM media HLS videos basically , is there any sample to implement the same.
DRM support in videojs is provided by a plugin - as mentioned in the videojs FAQ:
Support for DRM video via a core plugin
videojs-contrib-eme
The plugin is available here: https://github.com/videojs/videojs-contrib-eme
This includes usage instructions and tests on major browsers.
u can refer DRM in HLS stream in videojs-contrib-hls and videojs-contrib-eme
And sample code as
const options = {
"preload": "auto",
"width":"600 px",
hls: {
withCredentials: true
},
plugins: {
videoJsResolutionSwitcher: {
// default: 'high',
dynamicLabel: true
}
},
html5: {
nativeCaptions: false,
dash: {
setLimitBitrateByPortal: false,
// setMaxAllowedBitrateFor: ['video', 2000]
}
}
};
videojs.options.flash.swf = "http://vjs.zencdn.net/4.2/video-js.swf"
video = videojs("your videotag id");
video.src([
{
type: "application/x-mpegURL",
src: "your url",
keySystemOptions: [
{
name: 'com.widevine.alpha',
options: {
serverURL: 'http://m.widevine.com/proxy'
}
}
]
}
]);
to add videojs-contrib-eme with CND you can checkout :
https://www.jsdelivr.com/package/npm/videojs-contrib-eme
This is weird, I can use Phonegap's navigator object fine if I click a button on my page like so.
Controller
Ext.define('App.controller.MainController', {
extend: 'Ext.app.Controller',
config: {
refs: {
homeButton: 'button[action=viewHome]',
},
control: {
homeButton: {
tap: 'showHome'
},
}
},
showHome: function(button, e, options) {
navigator.notification.vibrate(1000);
},}
But if I try to access the navigator object in the launch function I get 'undefined'.
Controller
Ext.define('App.controller.MainController', {
extend: 'Ext.app.Controller',
launch: function(){
navigator.notification.vibrate(1000);
},}
The same thing is happening in app.js's launch function. Anybody know why is that and how I can use Phonegap in the launch function?
It seems you are trying to access the phonegap 'navigator' API, before it is ready. You have to listen for the deviceready event and once its triggered, you can call navigator.
You can call it this way.
launch: function () {
if(Ext.browser.is.PhoneGap && !Ext.os.is.Desktop) {
document.addEventListener("deviceready", this.mainLaunch, false);
} else {
this.mainLaunch();
}
},
mainLaunch: function() {
navigator.notification.vibrate(1000);
}
The Ext.browser check is to make this work on chrome browser also, otherwise you will have to always test the app on Simulator, or device.