Merge branch 'develop' into new/android-migration
This commit is contained in:
commit
53496efa6c
|
@ -81,6 +81,7 @@ import com.android.build.OutputFile
|
||||||
|
|
||||||
project.ext.react = [
|
project.ext.react = [
|
||||||
entryFile: "index.js",
|
entryFile: "index.js",
|
||||||
|
bundleAssetName: "app.bundle",
|
||||||
iconFontNames: [ 'custom.ttf' ],
|
iconFontNames: [ 'custom.ttf' ],
|
||||||
enableHermes: false, // clean and rebuild if changing
|
enableHermes: false, // clean and rebuild if changing
|
||||||
]
|
]
|
||||||
|
@ -225,6 +226,12 @@ dependencies {
|
||||||
implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') {
|
implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
|
implementation(project(':react-native-jitsi-meet')) {
|
||||||
|
exclude group: 'com.facebook.react', module:'react-native-fast-image'
|
||||||
|
exclude group: 'com.facebook.react', module:'react-native-vector-icons'
|
||||||
|
exclude group: 'com.facebook.react', module:'react-native-webview'
|
||||||
|
exclude group: 'com.facebook.react', module:'react-native-background-timer'
|
||||||
|
}
|
||||||
|
|
||||||
if (enableHermes) {
|
if (enableHermes) {
|
||||||
def hermesPath = "../../node_modules/hermesvm/android/";
|
def hermesPath = "../../node_modules/hermesvm/android/";
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
||||||
ÖŠ<EFBFBD>tùþ춥Z'ŸFöà.â°'
|
|
|
@ -6,6 +6,8 @@ import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.facebook.react.PackageList;
|
import com.facebook.react.PackageList;
|
||||||
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
|
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
|
||||||
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||||
|
@ -33,6 +35,7 @@ import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
|
||||||
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
|
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
|
||||||
|
|
||||||
import com.nozbe.watermelondb.WatermelonDBPackage;
|
import com.nozbe.watermelondb.WatermelonDBPackage;
|
||||||
|
import com.reactnativejitsimeet.JitsiMeetPackage;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -57,6 +60,7 @@ public class MainApplication extends Application implements ReactApplication, IN
|
||||||
packages.add(new KeyboardInputPackage(MainApplication.this));
|
packages.add(new KeyboardInputPackage(MainApplication.this));
|
||||||
packages.add(new RNNotificationsPackage(MainApplication.this));
|
packages.add(new RNNotificationsPackage(MainApplication.this));
|
||||||
packages.add(new WatermelonDBPackage());
|
packages.add(new WatermelonDBPackage());
|
||||||
|
packages.add(new JitsiMeetPackage());
|
||||||
packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));
|
packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));
|
||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +69,11 @@ public class MainApplication extends Application implements ReactApplication, IN
|
||||||
protected String getJSMainModuleName() {
|
protected String getJSMainModuleName() {
|
||||||
return "index";
|
return "index";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable String getBundleAssetName() {
|
||||||
|
return "app.bundle";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -41,6 +41,9 @@ allprojects {
|
||||||
// Android JSC is installed from npm
|
// Android JSC is installed from npm
|
||||||
url("$rootDir/../node_modules/jsc-android/dist")
|
url("$rootDir/../node_modules/jsc-android/dist")
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
|
||||||
|
}
|
||||||
|
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
|
|
@ -8,5 +8,7 @@ include ':reactnativenotifications'
|
||||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
|
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
|
||||||
include ':reactnativekeyboardinput'
|
include ':reactnativekeyboardinput'
|
||||||
project(':reactnativekeyboardinput').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-input/lib/android')
|
project(':reactnativekeyboardinput').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-input/lib/android')
|
||||||
|
include ':react-native-jitsi-meet'
|
||||||
|
project(':react-native-jitsi-meet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-jitsi-meet/android')
|
||||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||||
include ':app'
|
include ':app'
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
import { View, Animated } from 'react-native';
|
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default class Panel extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
open: PropTypes.bool.isRequired,
|
|
||||||
children: PropTypes.node.isRequired,
|
|
||||||
style: PropTypes.object
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
animation: new Animated.Value()
|
|
||||||
};
|
|
||||||
this.first = true;
|
|
||||||
this.open = false;
|
|
||||||
this.opacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { animation } = this.state;
|
|
||||||
const { open } = this.props;
|
|
||||||
const initialValue = !open ? this.height : 0;
|
|
||||||
animation.setValue(initialValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
const { animation } = this.state;
|
|
||||||
const { open } = this.props;
|
|
||||||
|
|
||||||
if (this.first) {
|
|
||||||
this.first = false;
|
|
||||||
if (!open) {
|
|
||||||
animation.setValue(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.open === nextProps.open) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.open = nextProps.open;
|
|
||||||
const initialValue = !nextProps.open ? this.height : 0;
|
|
||||||
const finalValue = !nextProps.open ? 0 : this.height;
|
|
||||||
|
|
||||||
animation.setValue(initialValue);
|
|
||||||
Animated.timing(
|
|
||||||
animation,
|
|
||||||
{
|
|
||||||
toValue: finalValue,
|
|
||||||
duration: 150,
|
|
||||||
useNativeDriver: true
|
|
||||||
}
|
|
||||||
).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
set _height(h) {
|
|
||||||
this.height = h || this.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { animation } = this.state;
|
|
||||||
const { style, children } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Animated.View
|
|
||||||
style={[{ height: animation }, style]}
|
|
||||||
>
|
|
||||||
<View onLayout={({ nativeEvent }) => this._height = nativeEvent.layout.height} style={{ position: !this.first ? 'relative' : 'absolute' }}>
|
|
||||||
{children}
|
|
||||||
</View>
|
|
||||||
</Animated.View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import { Animated, Text } from 'react-native';
|
|
||||||
|
|
||||||
export default class Fade extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
visible: PropTypes.bool.isRequired,
|
|
||||||
style: Animated.View.propTypes.style,
|
|
||||||
children: PropTypes.oneOfType([
|
|
||||||
PropTypes.arrayOf(PropTypes.node),
|
|
||||||
PropTypes.node
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
const { visible } = this.props;
|
|
||||||
this.state = {
|
|
||||||
visible
|
|
||||||
};
|
|
||||||
this._visibility = new Animated.Value(visible ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
if (nextProps.visible) {
|
|
||||||
this.setState({ visible: true });
|
|
||||||
}
|
|
||||||
Animated.timing(this._visibility, {
|
|
||||||
toValue: nextProps.visible ? 1 : 0,
|
|
||||||
duration: 300,
|
|
||||||
useNativeDriver: true
|
|
||||||
}).start(() => {
|
|
||||||
this.setState({ visible: nextProps.visible });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { visible } = this.state;
|
|
||||||
const { style, children, ...rest } = this.props;
|
|
||||||
|
|
||||||
const containerStyle = {
|
|
||||||
opacity: this._visibility.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, 1]
|
|
||||||
}),
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
scale: this._visibility.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [1.1, 1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const combinedStyle = [containerStyle, style];
|
|
||||||
return (
|
|
||||||
<Animated.View style={visible ? combinedStyle : containerStyle} {...rest}>
|
|
||||||
<Text>{visible ? children : null}</Text>
|
|
||||||
</Animated.View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,6 +23,18 @@ export default {
|
||||||
LDAP_Enable: {
|
LDAP_Enable: {
|
||||||
type: 'valueAsBoolean'
|
type: 'valueAsBoolean'
|
||||||
},
|
},
|
||||||
|
Jitsi_Enabled: {
|
||||||
|
type: 'valueAsBoolean'
|
||||||
|
},
|
||||||
|
Jitsi_SSL: {
|
||||||
|
type: 'valueAsBoolean'
|
||||||
|
},
|
||||||
|
Jitsi_Domain: {
|
||||||
|
type: 'valueAsString'
|
||||||
|
},
|
||||||
|
Jitsi_URL_Room_Prefix: {
|
||||||
|
type: 'valueAsString'
|
||||||
|
},
|
||||||
Message_AllowDeleting: {
|
Message_AllowDeleting: {
|
||||||
type: 'valueAsBoolean'
|
type: 'valueAsBoolean'
|
||||||
},
|
},
|
||||||
|
@ -56,6 +68,9 @@ export default {
|
||||||
Store_Last_Message: {
|
Store_Last_Message: {
|
||||||
type: 'valueAsBoolean'
|
type: 'valueAsBoolean'
|
||||||
},
|
},
|
||||||
|
uniqueID: {
|
||||||
|
type: 'valueAsString'
|
||||||
|
},
|
||||||
UI_Use_Real_Name: {
|
UI_Use_Real_Name: {
|
||||||
type: 'valueAsBoolean'
|
type: 'valueAsBoolean'
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { View, Text } from 'react-native';
|
||||||
|
import Touchable from 'react-native-platform-touchable';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { formatLastMessage, BUTTON_HIT_SLOP } from './utils';
|
||||||
|
import styles from './styles';
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
|
|
||||||
|
const CallButton = React.memo(({
|
||||||
|
dlm, callJitsi
|
||||||
|
}) => {
|
||||||
|
const time = formatLastMessage(dlm);
|
||||||
|
return (
|
||||||
|
<View style={styles.buttonContainer}>
|
||||||
|
<Touchable
|
||||||
|
onPress={callJitsi}
|
||||||
|
background={Touchable.Ripple('#fff')}
|
||||||
|
style={[styles.button, styles.smallButton]}
|
||||||
|
hitSlop={BUTTON_HIT_SLOP}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<CustomIcon name='video' size={20} style={styles.buttonIcon} />
|
||||||
|
<Text style={styles.buttonText}>{I18n.t('Click_to_join')}</Text>
|
||||||
|
</>
|
||||||
|
</Touchable>
|
||||||
|
<Text style={styles.time}>{time}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CallButton.propTypes = {
|
||||||
|
dlm: PropTypes.string,
|
||||||
|
callJitsi: PropTypes.func
|
||||||
|
};
|
||||||
|
CallButton.displayName = 'CallButton';
|
||||||
|
|
||||||
|
export default CallButton;
|
|
@ -16,6 +16,7 @@ import Broadcast from './Broadcast';
|
||||||
import Discussion from './Discussion';
|
import Discussion from './Discussion';
|
||||||
import Content from './Content';
|
import Content from './Content';
|
||||||
import ReadReceipt from './ReadReceipt';
|
import ReadReceipt from './ReadReceipt';
|
||||||
|
import CallButton from './CallButton';
|
||||||
|
|
||||||
const MessageInner = React.memo((props) => {
|
const MessageInner = React.memo((props) => {
|
||||||
if (props.type === 'discussion-created') {
|
if (props.type === 'discussion-created') {
|
||||||
|
@ -26,6 +27,15 @@ const MessageInner = React.memo((props) => {
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (props.type === 'jitsi_call_started') {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<User {...props} />
|
||||||
|
<Content {...props} isInfo />
|
||||||
|
<CallButton {...props} />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<User {...props} />
|
<User {...props} />
|
||||||
|
|
|
@ -41,7 +41,8 @@ export default class MessageContainer extends React.Component {
|
||||||
fetchThreadName: PropTypes.func,
|
fetchThreadName: PropTypes.func,
|
||||||
onOpenFileModal: PropTypes.func,
|
onOpenFileModal: PropTypes.func,
|
||||||
onReactionLongPress: PropTypes.func,
|
onReactionLongPress: PropTypes.func,
|
||||||
navToRoomInfo: PropTypes.func
|
navToRoomInfo: PropTypes.func,
|
||||||
|
callJitsi: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -204,7 +205,7 @@ export default class MessageContainer extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage, navToRoomInfo, getCustomEmoji, isThreadRoom
|
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage, navToRoomInfo, getCustomEmoji, isThreadRoom, callJitsi
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
id, msg, ts, attachments, urls, reactions, t, avatar, u, alias, editedBy, role, drid, dcount, dlm, tmid, tcount, tlm, tmsg, mentions, channels, unread, autoTranslate: autoTranslateMessage
|
id, msg, ts, attachments, urls, reactions, t, avatar, u, alias, editedBy, role, drid, dcount, dlm, tmid, tcount, tlm, tmsg, mentions, channels, unread, autoTranslate: autoTranslateMessage
|
||||||
|
@ -270,6 +271,7 @@ export default class MessageContainer extends React.Component {
|
||||||
onOpenFileModal={onOpenFileModal}
|
onOpenFileModal={onOpenFileModal}
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
navToRoomInfo={navToRoomInfo}
|
navToRoomInfo={navToRoomInfo}
|
||||||
|
callJitsi={callJitsi}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ export const getInfoMessage = ({
|
||||||
return I18n.t('Room_name_changed', { name: msg, userBy: username });
|
return I18n.t('Room_name_changed', { name: msg, userBy: username });
|
||||||
} else if (type === 'message_pinned') {
|
} else if (type === 'message_pinned') {
|
||||||
return I18n.t('Message_pinned');
|
return I18n.t('Message_pinned');
|
||||||
|
} else if (type === 'jitsi_call_started') {
|
||||||
|
return I18n.t('Started_call', { userBy: username });
|
||||||
} else if (type === 'ul') {
|
} else if (type === 'ul') {
|
||||||
return I18n.t('Has_left_the_channel');
|
return I18n.t('Has_left_the_channel');
|
||||||
} else if (type === 'ru') {
|
} else if (type === 'ru') {
|
||||||
|
|
|
@ -120,6 +120,8 @@ export default {
|
||||||
Channel_Name: 'Channel Name',
|
Channel_Name: 'Channel Name',
|
||||||
Channels: 'Channels',
|
Channels: 'Channels',
|
||||||
Chats: 'Chats',
|
Chats: 'Chats',
|
||||||
|
Call_already_ended: 'Call already ended!',
|
||||||
|
Click_to_join: 'Click to Join!',
|
||||||
Close: 'Close',
|
Close: 'Close',
|
||||||
Close_emoji_selector: 'Close emoji selector',
|
Close_emoji_selector: 'Close emoji selector',
|
||||||
Choose: 'Choose',
|
Choose: 'Choose',
|
||||||
|
@ -364,6 +366,7 @@ export default {
|
||||||
Starred: 'Starred',
|
Starred: 'Starred',
|
||||||
Start_of_conversation: 'Start of conversation',
|
Start_of_conversation: 'Start of conversation',
|
||||||
Started_discussion: 'Started a discussion:',
|
Started_discussion: 'Started a discussion:',
|
||||||
|
Started_call: 'Call started by {{userBy}}',
|
||||||
Submit: 'Submit',
|
Submit: 'Submit',
|
||||||
Table: 'Table',
|
Table: 'Table',
|
||||||
Take_a_photo: 'Take a photo',
|
Take_a_photo: 'Take a photo',
|
||||||
|
|
|
@ -122,6 +122,8 @@ export default {
|
||||||
Channel_Name: 'Nome do Canal',
|
Channel_Name: 'Nome do Canal',
|
||||||
Channels: 'Canais',
|
Channels: 'Canais',
|
||||||
Chats: 'Conversas',
|
Chats: 'Conversas',
|
||||||
|
Call_already_ended: 'A chamada já terminou!',
|
||||||
|
Click_to_join: 'Clique para participar!',
|
||||||
Close: 'Fechar',
|
Close: 'Fechar',
|
||||||
Close_emoji_selector: 'Fechar seletor de emojis',
|
Close_emoji_selector: 'Fechar seletor de emojis',
|
||||||
Choose: 'Escolher',
|
Choose: 'Escolher',
|
||||||
|
@ -325,6 +327,7 @@ export default {
|
||||||
starred: 'favoritou',
|
starred: 'favoritou',
|
||||||
Starred: 'Mensagens Favoritas',
|
Starred: 'Mensagens Favoritas',
|
||||||
Start_of_conversation: 'Início da conversa',
|
Start_of_conversation: 'Início da conversa',
|
||||||
|
Started_call: 'Chamada iniciada por {{userBy}}',
|
||||||
Started_discussion: 'Iniciou uma discussão:',
|
Started_discussion: 'Iniciou uma discussão:',
|
||||||
Submit: 'Enviar',
|
Submit: 'Enviar',
|
||||||
Table: 'Tabela',
|
Table: 'Tabela',
|
||||||
|
|
15
app/index.js
15
app/index.js
|
@ -19,6 +19,7 @@ import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
||||||
import { loggerConfig, analytics } from './utils/log';
|
import { loggerConfig, analytics } from './utils/log';
|
||||||
import Toast from './containers/Toast';
|
import Toast from './containers/Toast';
|
||||||
import RocketChat from './lib/rocketchat';
|
import RocketChat from './lib/rocketchat';
|
||||||
|
import LayoutAnimation from './utils/layoutAnimation';
|
||||||
|
|
||||||
useScreens();
|
useScreens();
|
||||||
|
|
||||||
|
@ -308,12 +309,14 @@ export default class Root extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App
|
<LayoutAnimation>
|
||||||
ref={(navigatorRef) => {
|
<App
|
||||||
Navigation.setTopLevelNavigator(navigatorRef);
|
ref={(navigatorRef) => {
|
||||||
}}
|
Navigation.setTopLevelNavigator(navigatorRef);
|
||||||
onNavigationStateChange={onNavigationStateChange}
|
}}
|
||||||
/>
|
onNavigationStateChange={onNavigationStateChange}
|
||||||
|
/>
|
||||||
|
</LayoutAnimation>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import Server from './model/Server';
|
||||||
import serversSchema from './schema/servers';
|
import serversSchema from './schema/servers';
|
||||||
import appSchema from './schema/app';
|
import appSchema from './schema/app';
|
||||||
|
|
||||||
|
import migrations from './model/migrations';
|
||||||
|
|
||||||
import { isIOS } from '../../utils/deviceInfo';
|
import { isIOS } from '../../utils/deviceInfo';
|
||||||
|
|
||||||
const appGroupPath = isIOS ? `${ RNFetchBlob.fs.syncPathAppGroup('group.ios.chat.rocket') }/` : '';
|
const appGroupPath = isIOS ? `${ RNFetchBlob.fs.syncPathAppGroup('group.ios.chat.rocket') }/` : '';
|
||||||
|
@ -54,7 +56,8 @@ class DB {
|
||||||
|
|
||||||
const adapter = new SQLiteAdapter({
|
const adapter = new SQLiteAdapter({
|
||||||
dbName,
|
dbName,
|
||||||
schema: appSchema
|
schema: appSchema,
|
||||||
|
migrations
|
||||||
});
|
});
|
||||||
|
|
||||||
this.databases.activeDB = new Database({
|
this.databases.activeDB = new Database({
|
||||||
|
|
|
@ -74,6 +74,8 @@ export default class Subscription extends Model {
|
||||||
|
|
||||||
@date('last_thread_sync') lastThreadSync;
|
@date('last_thread_sync') lastThreadSync;
|
||||||
|
|
||||||
|
@date('jitsi_timeout') jitsiTimeout;
|
||||||
|
|
||||||
@field('auto_translate') autoTranslate;
|
@field('auto_translate') autoTranslate;
|
||||||
|
|
||||||
@field('auto_translate_language') autoTranslateLanguage;
|
@field('auto_translate_language') autoTranslateLanguage;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { schemaMigrations, addColumns } from '@nozbe/watermelondb/Schema/migrations';
|
||||||
|
|
||||||
|
export default schemaMigrations({
|
||||||
|
migrations: [
|
||||||
|
{
|
||||||
|
toVersion: 2,
|
||||||
|
steps: [
|
||||||
|
addColumns({
|
||||||
|
table: 'subscriptions',
|
||||||
|
columns: [
|
||||||
|
{ name: 'jitsi_timeout', type: 'number', isOptional: true }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
|
@ -1,7 +1,7 @@
|
||||||
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
||||||
|
|
||||||
export default appSchema({
|
export default appSchema({
|
||||||
version: 1,
|
version: 2,
|
||||||
tables: [
|
tables: [
|
||||||
tableSchema({
|
tableSchema({
|
||||||
name: 'subscriptions',
|
name: 'subscriptions',
|
||||||
|
@ -36,6 +36,7 @@ export default appSchema({
|
||||||
{ name: 'prid', type: 'string', isOptional: true },
|
{ name: 'prid', type: 'string', isOptional: true },
|
||||||
{ name: 'draft_message', type: 'string', isOptional: true },
|
{ name: 'draft_message', type: 'string', isOptional: true },
|
||||||
{ name: 'last_thread_sync', type: 'number', isOptional: true },
|
{ name: 'last_thread_sync', type: 'number', isOptional: true },
|
||||||
|
{ name: 'jitsi_timeout', type: 'number', isOptional: true },
|
||||||
{ name: 'auto_translate', type: 'boolean', isOptional: true },
|
{ name: 'auto_translate', type: 'boolean', isOptional: true },
|
||||||
{ name: 'auto_translate_language', type: 'string' }
|
{ name: 'auto_translate_language', type: 'string' }
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import JitsiMeet, { JitsiMeetEvents } from 'react-native-jitsi-meet';
|
||||||
|
import BackgroundTimer from 'react-native-background-timer';
|
||||||
|
|
||||||
|
import reduxStore from '../createStore';
|
||||||
|
|
||||||
|
let jitsiTimeout = null;
|
||||||
|
|
||||||
|
const jitsiBaseUrl = ({
|
||||||
|
Jitsi_Enabled, Jitsi_SSL, Jitsi_Domain, Jitsi_URL_Room_Prefix, uniqueID
|
||||||
|
}) => {
|
||||||
|
if (!Jitsi_Enabled) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const uniqueIdentifier = uniqueID || 'undefined';
|
||||||
|
const domain = Jitsi_Domain;
|
||||||
|
const prefix = Jitsi_URL_Room_Prefix;
|
||||||
|
|
||||||
|
const urlProtocol = Jitsi_SSL ? 'https://' : 'http://';
|
||||||
|
const urlDomain = `${ domain }/`;
|
||||||
|
|
||||||
|
return `${ urlProtocol }${ urlDomain }${ prefix }${ uniqueIdentifier }`;
|
||||||
|
};
|
||||||
|
|
||||||
|
function callJitsi(rid, options = {}) {
|
||||||
|
const { settings } = reduxStore.getState();
|
||||||
|
|
||||||
|
// Jitsi Update Timeout needs to be called every 10 seconds to make sure
|
||||||
|
// call is not ended and is available to web users.
|
||||||
|
JitsiMeet.initialize();
|
||||||
|
const conferenceJoined = JitsiMeetEvents.addListener('CONFERENCE_JOINED', () => {
|
||||||
|
this.updateJitsiTimeout(rid).catch(e => console.log(e));
|
||||||
|
if (jitsiTimeout) {
|
||||||
|
BackgroundTimer.clearInterval(jitsiTimeout);
|
||||||
|
}
|
||||||
|
jitsiTimeout = BackgroundTimer.setInterval(() => {
|
||||||
|
this.updateJitsiTimeout(rid).catch(e => console.log(e));
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
const conferenceLeft = JitsiMeetEvents.addListener('CONFERENCE_LEFT', () => {
|
||||||
|
if (jitsiTimeout) {
|
||||||
|
BackgroundTimer.clearInterval(jitsiTimeout);
|
||||||
|
}
|
||||||
|
if (conferenceJoined && conferenceJoined.remove) {
|
||||||
|
conferenceJoined.remove();
|
||||||
|
}
|
||||||
|
if (conferenceLeft && conferenceLeft.remove) {
|
||||||
|
conferenceLeft.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JitsiMeet.call(`${ jitsiBaseUrl(settings) }${ rid }`, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default callJitsi;
|
|
@ -20,6 +20,7 @@ export const merge = (subscription, room) => {
|
||||||
subscription.reactWhenReadOnly = room.reactWhenReadOnly;
|
subscription.reactWhenReadOnly = room.reactWhenReadOnly;
|
||||||
subscription.archived = room.archived || false;
|
subscription.archived = room.archived || false;
|
||||||
subscription.joinCodeRequired = room.joinCodeRequired;
|
subscription.joinCodeRequired = room.joinCodeRequired;
|
||||||
|
subscription.jitsiTimeout = room.jitsiTimeout;
|
||||||
}
|
}
|
||||||
subscription.ro = room.ro;
|
subscription.ro = room.ro;
|
||||||
subscription.broadcast = room.broadcast;
|
subscription.broadcast = room.broadcast;
|
||||||
|
|
|
@ -58,6 +58,7 @@ const createOrUpdateSubscription = async(subscription, room) => {
|
||||||
prid: s.prid,
|
prid: s.prid,
|
||||||
draftMessage: s.draftMessage,
|
draftMessage: s.draftMessage,
|
||||||
lastThreadSync: s.lastThreadSync,
|
lastThreadSync: s.lastThreadSync,
|
||||||
|
jitsiTimeout: s.jitsiTimeout,
|
||||||
autoTranslate: s.autoTranslate,
|
autoTranslate: s.autoTranslate,
|
||||||
autoTranslateLanguage: s.autoTranslateLanguage,
|
autoTranslateLanguage: s.autoTranslateLanguage,
|
||||||
lastMessage: s.lastMessage
|
lastMessage: s.lastMessage
|
||||||
|
|
|
@ -42,6 +42,8 @@ import loadThreadMessages from './methods/loadThreadMessages';
|
||||||
import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage';
|
import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage';
|
||||||
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
|
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
|
||||||
|
|
||||||
|
import callJitsi from './methods/callJitsi';
|
||||||
|
|
||||||
import { getDeviceToken } from '../notifications/push';
|
import { getDeviceToken } from '../notifications/push';
|
||||||
import { SERVERS, SERVER_URL } from '../constants/credentials';
|
import { SERVERS, SERVER_URL } from '../constants/credentials';
|
||||||
import { setActiveUsers } from '../actions/activeUsers';
|
import { setActiveUsers } from '../actions/activeUsers';
|
||||||
|
@ -57,6 +59,7 @@ const STATUSES = ['offline', 'online', 'away', 'busy'];
|
||||||
|
|
||||||
const RocketChat = {
|
const RocketChat = {
|
||||||
TOKEN_KEY,
|
TOKEN_KEY,
|
||||||
|
callJitsi,
|
||||||
async subscribeRooms() {
|
async subscribeRooms() {
|
||||||
if (this.roomsSub) {
|
if (this.roomsSub) {
|
||||||
this.roomsSub.stop();
|
this.roomsSub.stop();
|
||||||
|
@ -246,6 +249,10 @@ const RocketChat = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateJitsiTimeout(rid) {
|
||||||
|
return this.sdk.methodCall('jitsi:updateTimeout', rid);
|
||||||
|
},
|
||||||
|
|
||||||
register(credentials) {
|
register(credentials) {
|
||||||
// RC 0.50.0
|
// RC 0.50.0
|
||||||
return this.sdk.post('users.register', credentials, false);
|
return this.sdk.post('users.register', credentials, false);
|
||||||
|
|
|
@ -16,6 +16,10 @@ const formatMsg = ({
|
||||||
if (!lastMessage || lastMessage.pinned) {
|
if (!lastMessage || lastMessage.pinned) {
|
||||||
return I18n.t('No_Message');
|
return I18n.t('No_Message');
|
||||||
}
|
}
|
||||||
|
if (lastMessage.t === 'jitsi_call_started') {
|
||||||
|
const { u } = lastMessage;
|
||||||
|
return I18n.t('Started_call', { userBy: u.username });
|
||||||
|
}
|
||||||
|
|
||||||
let prefix = '';
|
let prefix = '';
|
||||||
const isLastMessageSentByMe = lastMessage.u.username === username;
|
const isLastMessageSentByMe = lastMessage.u.username === username;
|
||||||
|
|
15
app/share.js
15
app/share.js
|
@ -11,6 +11,7 @@ import sharedStyles from './views/Styles';
|
||||||
import { isNotch } from './utils/deviceInfo';
|
import { isNotch } from './utils/deviceInfo';
|
||||||
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
||||||
import RocketChat from './lib/rocketchat';
|
import RocketChat from './lib/rocketchat';
|
||||||
|
import LayoutAnimation from './utils/layoutAnimation';
|
||||||
|
|
||||||
import { IDENTIFIER } from './constants/credentials';
|
import { IDENTIFIER } from './constants/credentials';
|
||||||
|
|
||||||
|
@ -84,12 +85,14 @@ class Root extends React.Component {
|
||||||
onLayout={this.handleLayout}
|
onLayout={this.handleLayout}
|
||||||
>
|
>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<AppContainer
|
<LayoutAnimation>
|
||||||
ref={(navigatorRef) => {
|
<AppContainer
|
||||||
Navigation.setTopLevelNavigator(navigatorRef);
|
ref={(navigatorRef) => {
|
||||||
}}
|
Navigation.setTopLevelNavigator(navigatorRef);
|
||||||
onNavigationStateChange={onNavigationStateChange}
|
}}
|
||||||
/>
|
onNavigationStateChange={onNavigationStateChange}
|
||||||
|
/>
|
||||||
|
</LayoutAnimation>
|
||||||
</Provider>
|
</Provider>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Transition, Transitioning } from 'react-native-reanimated';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import debounce from './debounce';
|
||||||
|
import { isIOS } from './deviceInfo';
|
||||||
|
import sharedStyles from '../views/Styles';
|
||||||
|
|
||||||
|
const transition = (
|
||||||
|
<Transition.Together>
|
||||||
|
<Transition.In type='fade' />
|
||||||
|
<Transition.Out type='fade' />
|
||||||
|
<Transition.Change interpolation='easeInOut' />
|
||||||
|
</Transition.Together>
|
||||||
|
);
|
||||||
|
|
||||||
|
const TRANSITION_REF = React.createRef();
|
||||||
|
|
||||||
|
export const animateNextTransition = debounce(() => {
|
||||||
|
if (isIOS) {
|
||||||
|
TRANSITION_REF.current.animateNextTransition();
|
||||||
|
}
|
||||||
|
}, 200, true);
|
||||||
|
|
||||||
|
const LayoutAnimation = ({ children }) => {
|
||||||
|
if (isIOS) {
|
||||||
|
return (
|
||||||
|
<Transitioning.View
|
||||||
|
style={sharedStyles.root}
|
||||||
|
transition={transition}
|
||||||
|
ref={TRANSITION_REF}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Transitioning.View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
||||||
|
LayoutAnimation.propTypes = {
|
||||||
|
children: PropTypes.node
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LayoutAnimation;
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Keyboard, Text, ScrollView, View, StyleSheet, Alert, LayoutAnimation
|
Keyboard, Text, ScrollView, View, StyleSheet, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { SafeAreaView } from 'react-navigation';
|
||||||
|
@ -18,6 +18,7 @@ import { loginRequest as loginRequestAction } from '../actions/login';
|
||||||
import { LegalButton } from '../containers/HeaderButton';
|
import { LegalButton } from '../containers/HeaderButton';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import StatusBar from '../containers/StatusBar';
|
||||||
import { COLOR_PRIMARY } from '../constants/colors';
|
import { COLOR_PRIMARY } from '../constants/colors';
|
||||||
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
bottomContainer: {
|
bottomContainer: {
|
||||||
|
@ -84,7 +85,7 @@ class LoginView extends React.Component {
|
||||||
this.setTitle(nextProps.Site_Name);
|
this.setTitle(nextProps.Site_Name);
|
||||||
} else if (nextProps.failure && !equal(error, nextProps.error)) {
|
} else if (nextProps.failure && !equal(error, nextProps.error)) {
|
||||||
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
this.setState({ showTOTP: true });
|
this.setState({ showTOTP: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity, View, Alert, LayoutAnimation
|
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity, View, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { SafeAreaView } from 'react-navigation';
|
||||||
|
@ -23,6 +23,7 @@ import { CustomIcon } from '../lib/Icons';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import StatusBar from '../containers/StatusBar';
|
||||||
import { COLOR_PRIMARY } from '../constants/colors';
|
import { COLOR_PRIMARY } from '../constants/colors';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
image: {
|
image: {
|
||||||
|
@ -195,7 +196,7 @@ class NewServerView extends React.Component {
|
||||||
uriToPath = uri => uri.replace('file://', '');
|
uriToPath = uri => uri.replace('file://', '');
|
||||||
|
|
||||||
saveCertificate = (certificate) => {
|
saveCertificate = (certificate) => {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
this.setState({ certificate });
|
this.setState({ certificate });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ class RoomActionsView extends React.Component {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
token: PropTypes.string
|
token: PropTypes.string
|
||||||
}),
|
}),
|
||||||
leaveRoom: PropTypes.func
|
leaveRoom: PropTypes.func,
|
||||||
|
jitsiEnabled: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -164,6 +165,7 @@ class RoomActionsView extends React.Component {
|
||||||
const {
|
const {
|
||||||
room, membersCount, canViewMembers, canAddUser, joined, canAutoTranslate
|
room, membersCount, canViewMembers, canAddUser, joined, canAutoTranslate
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
const { jitsiEnabled } = this.props;
|
||||||
const {
|
const {
|
||||||
rid, t, blocker
|
rid, t, blocker
|
||||||
} = room;
|
} = room;
|
||||||
|
@ -176,6 +178,21 @@ class RoomActionsView extends React.Component {
|
||||||
testID: 'room-actions-notifications'
|
testID: 'room-actions-notifications'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const jitsiActions = jitsiEnabled ? [
|
||||||
|
{
|
||||||
|
icon: 'livechat',
|
||||||
|
name: I18n.t('Voice_call'),
|
||||||
|
event: () => RocketChat.callJitsi(rid, { videoMuted: true }),
|
||||||
|
testID: 'room-actions-voice'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'video',
|
||||||
|
name: I18n.t('Video_call'),
|
||||||
|
event: () => RocketChat.callJitsi(rid),
|
||||||
|
testID: 'room-actions-video'
|
||||||
|
}
|
||||||
|
] : [];
|
||||||
|
|
||||||
const sections = [{
|
const sections = [{
|
||||||
data: [{
|
data: [{
|
||||||
icon: 'star',
|
icon: 'star',
|
||||||
|
@ -187,20 +204,7 @@ class RoomActionsView extends React.Component {
|
||||||
}],
|
}],
|
||||||
renderItem: this.renderRoomInfo
|
renderItem: this.renderRoomInfo
|
||||||
}, {
|
}, {
|
||||||
data: [
|
data: jitsiActions,
|
||||||
{
|
|
||||||
icon: 'livechat',
|
|
||||||
name: I18n.t('Voice_call'),
|
|
||||||
disabled: true,
|
|
||||||
testID: 'room-actions-voice'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'video',
|
|
||||||
name: I18n.t('Video_call'),
|
|
||||||
disabled: true,
|
|
||||||
testID: 'room-actions-video'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
}, {
|
}, {
|
||||||
data: [
|
data: [
|
||||||
|
@ -477,7 +481,8 @@ const mapStateToProps = state => ({
|
||||||
id: state.login.user && state.login.user.id,
|
id: state.login.user && state.login.user.id,
|
||||||
token: state.login.user && state.login.user.token
|
token: state.login.user && state.login.user.token
|
||||||
},
|
},
|
||||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||||
|
jitsiEnabled: state.settings.Jitsi_Enabled || false
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator, FlatList, InteractionManager, LayoutAnimation
|
ActivityIndicator, FlatList, InteractionManager
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
|
@ -15,6 +15,7 @@ import RocketChat from '../../lib/rocketchat';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import EmptyRoom from './EmptyRoom';
|
import EmptyRoom from './EmptyRoom';
|
||||||
import { isIOS } from '../../utils/deviceInfo';
|
import { isIOS } from '../../utils/deviceInfo';
|
||||||
|
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||||
|
|
||||||
export class List extends React.Component {
|
export class List extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -83,7 +84,7 @@ export class List extends React.Component {
|
||||||
}
|
}
|
||||||
const messages = orderBy(data, ['ts'], ['desc']);
|
const messages = orderBy(data, ['ts'], ['desc']);
|
||||||
if (this.mounted) {
|
if (this.mounted) {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
this.setState({ messages });
|
this.setState({ messages });
|
||||||
} else {
|
} else {
|
||||||
this.state.messages = messages;
|
this.state.messages = messages;
|
||||||
|
@ -186,11 +187,11 @@ export class List extends React.Component {
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
inverted
|
inverted
|
||||||
removeClippedSubviews={isIOS}
|
removeClippedSubviews={isIOS}
|
||||||
initialNumToRender={7}
|
// initialNumToRender={7}
|
||||||
onEndReached={this.onEndReached}
|
onEndReached={this.onEndReached}
|
||||||
onEndReachedThreshold={5}
|
// onEndReachedThreshold={5}
|
||||||
maxToRenderPerBatch={5}
|
// maxToRenderPerBatch={5}
|
||||||
windowSize={10}
|
// windowSize={10}
|
||||||
ListFooterComponent={this.renderFooter}
|
ListFooterComponent={this.renderFooter}
|
||||||
{...scrollPersistTaps}
|
{...scrollPersistTaps}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import { Text, View, InteractionManager } from 'react-native';
|
||||||
Text, View, InteractionManager, LayoutAnimation
|
|
||||||
} from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { RectButton } from 'react-native-gesture-handler';
|
import { RectButton } from 'react-native-gesture-handler';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { SafeAreaView } from 'react-navigation';
|
||||||
|
@ -39,6 +37,7 @@ import ReactionsModal from '../../containers/ReactionsModal';
|
||||||
import { LISTENER } from '../../containers/Toast';
|
import { LISTENER } from '../../containers/Toast';
|
||||||
import { isReadOnly, isBlocked } from '../../utils/room';
|
import { isReadOnly, isBlocked } from '../../utils/room';
|
||||||
import { isIOS } from '../../utils/deviceInfo';
|
import { isIOS } from '../../utils/deviceInfo';
|
||||||
|
import { showErrorAlert } from '../../utils/info';
|
||||||
|
|
||||||
const stateAttrsUpdate = [
|
const stateAttrsUpdate = [
|
||||||
'joined',
|
'joined',
|
||||||
|
@ -53,7 +52,7 @@ const stateAttrsUpdate = [
|
||||||
'replying',
|
'replying',
|
||||||
'reacting'
|
'reacting'
|
||||||
];
|
];
|
||||||
const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted'];
|
const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout'];
|
||||||
|
|
||||||
class RoomView extends React.Component {
|
class RoomView extends React.Component {
|
||||||
static navigationOptions = ({ navigation }) => {
|
static navigationOptions = ({ navigation }) => {
|
||||||
|
@ -483,15 +482,11 @@ class RoomView extends React.Component {
|
||||||
if (!this.mounted) {
|
if (!this.mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isIOS && this.beginAnimating) {
|
|
||||||
LayoutAnimation.easeInEaseOut();
|
|
||||||
}
|
|
||||||
this.setState(...args);
|
this.setState(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage = (message, tmid) => {
|
sendMessage = (message, tmid) => {
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
LayoutAnimation.easeInEaseOut();
|
|
||||||
RocketChat.sendMessage(this.rid, message, this.tmid || tmid, user).then(() => {
|
RocketChat.sendMessage(this.rid, message, this.tmid || tmid, user).then(() => {
|
||||||
this.setLastOpen(null);
|
this.setLastOpen(null);
|
||||||
});
|
});
|
||||||
|
@ -603,6 +598,16 @@ class RoomView extends React.Component {
|
||||||
navigation.navigate('RoomInfoView', navParam);
|
navigation.navigate('RoomInfoView', navParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callJitsi = () => {
|
||||||
|
const { room } = this.state;
|
||||||
|
const { jitsiTimeout } = room;
|
||||||
|
if (jitsiTimeout < Date.now()) {
|
||||||
|
showErrorAlert(I18n.t('Call_already_ended'));
|
||||||
|
} else {
|
||||||
|
RocketChat.callJitsi(this.rid, {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
get isReadOnly() {
|
get isReadOnly() {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
|
@ -658,6 +663,7 @@ class RoomView extends React.Component {
|
||||||
autoTranslateLanguage={room.autoTranslateLanguage}
|
autoTranslateLanguage={room.autoTranslateLanguage}
|
||||||
navToRoomInfo={this.navToRoomInfo}
|
navToRoomInfo={this.navToRoomInfo}
|
||||||
getCustomEmoji={this.getCustomEmoji}
|
getCustomEmoji={this.getCustomEmoji}
|
||||||
|
callJitsi={this.callJitsi}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {
|
||||||
Text,
|
Text,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
LayoutAnimation,
|
|
||||||
Dimensions
|
Dimensions
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -43,6 +42,7 @@ import {
|
||||||
import StatusBar from '../../containers/StatusBar';
|
import StatusBar from '../../containers/StatusBar';
|
||||||
import ListHeader from './ListHeader';
|
import ListHeader from './ListHeader';
|
||||||
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
||||||
|
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||||
|
|
||||||
const SCROLL_OFFSET = 56;
|
const SCROLL_OFFSET = 56;
|
||||||
|
|
||||||
|
@ -290,8 +290,8 @@ class RoomsListView extends React.Component {
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
internalSetState = (...args) => {
|
internalSetState = (...args) => {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
if (isIOS && navigation.isFocused()) {
|
if (navigation.isFocused()) {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
}
|
}
|
||||||
this.setState(...args);
|
this.setState(...args);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import { View, StyleSheet, FlatList } from 'react-native';
|
||||||
View, StyleSheet, FlatList, LayoutAnimation
|
|
||||||
} from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { SafeAreaView } from 'react-navigation';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
|
@ -25,6 +23,7 @@ import sharedStyles from './Styles';
|
||||||
import { Item, CustomHeaderButtons } from '../containers/HeaderButton';
|
import { Item, CustomHeaderButtons } from '../containers/HeaderButton';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import StatusBar from '../containers/StatusBar';
|
||||||
import { COLOR_WHITE } from '../constants/colors';
|
import { COLOR_WHITE } from '../constants/colors';
|
||||||
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
safeAreaView: {
|
safeAreaView: {
|
||||||
|
@ -169,7 +168,7 @@ class SelectedUsersView extends React.Component {
|
||||||
toggleUser = (user) => {
|
toggleUser = (user) => {
|
||||||
const { addUser, removeUser } = this.props;
|
const { addUser, removeUser } = this.props;
|
||||||
|
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
if (!this.isChecked(user.name)) {
|
if (!this.isChecked(user.name)) {
|
||||||
addUser(user);
|
addUser(user);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import { Keyboard, View, StyleSheet } from 'react-native';
|
||||||
Keyboard, LayoutAnimation, View, StyleSheet
|
|
||||||
} from 'react-native';
|
|
||||||
import ShareExtension from 'rn-extensions-share';
|
import ShareExtension from 'rn-extensions-share';
|
||||||
|
|
||||||
import SearchBox from '../../../containers/SearchBox';
|
import SearchBox from '../../../containers/SearchBox';
|
||||||
|
@ -10,6 +8,7 @@ import { CloseShareExtensionButton } from '../../../containers/HeaderButton';
|
||||||
import { HEADER_BACKGROUND } from '../../../constants/colors';
|
import { HEADER_BACKGROUND } from '../../../constants/colors';
|
||||||
|
|
||||||
import sharedStyles from '../../Styles';
|
import sharedStyles from '../../Styles';
|
||||||
|
import { animateNextTransition } from '../../../utils/layoutAnimation';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -33,12 +32,12 @@ const Header = React.memo(({
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
onChangeText('');
|
onChangeText('');
|
||||||
cancelSearch();
|
cancelSearch();
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
initSearch();
|
initSearch();
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
View, Text, LayoutAnimation, FlatList, ActivityIndicator, Keyboard, BackHandler
|
View, Text, FlatList, ActivityIndicator, Keyboard, BackHandler
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { SafeAreaView } from 'react-navigation';
|
||||||
import ShareExtension from 'rn-extensions-share';
|
import ShareExtension from 'rn-extensions-share';
|
||||||
|
@ -25,6 +25,7 @@ import ShareListHeader from './Header';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import StatusBar from '../../containers/StatusBar';
|
import StatusBar from '../../containers/StatusBar';
|
||||||
|
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||||
|
|
||||||
const LIMIT = 50;
|
const LIMIT = 50;
|
||||||
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
||||||
|
@ -174,8 +175,8 @@ class ShareListView extends React.Component {
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
internalSetState = (...args) => {
|
internalSetState = (...args) => {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
if (isIOS && navigation.isFocused()) {
|
if (navigation.isFocused()) {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
}
|
}
|
||||||
this.setState(...args);
|
this.setState(...args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
ScrollView, Text, View, FlatList, LayoutAnimation, SafeAreaView
|
ScrollView, Text, View, FlatList, SafeAreaView
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
|
@ -20,6 +20,7 @@ import styles from './styles';
|
||||||
import SidebarItem from './SidebarItem';
|
import SidebarItem from './SidebarItem';
|
||||||
import { COLOR_TEXT } from '../../constants/colors';
|
import { COLOR_TEXT } from '../../constants/colors';
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
|
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||||
|
|
||||||
const keyExtractor = item => item.id;
|
const keyExtractor = item => item.id;
|
||||||
|
|
||||||
|
@ -147,7 +148,7 @@ class Sidebar extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleStatus = () => {
|
toggleStatus = () => {
|
||||||
LayoutAnimation.easeInEaseOut();
|
animateNextTransition();
|
||||||
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@ import {
|
||||||
} from '../constants/colors';
|
} from '../constants/colors';
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
flex: 1
|
flex: 1
|
||||||
|
|
|
@ -174,18 +174,20 @@ describe('Room actions screen', () => {
|
||||||
|
|
||||||
describe('Usage', async() => {
|
describe('Usage', async() => {
|
||||||
describe('TDB', async() => {
|
describe('TDB', async() => {
|
||||||
it('should NOT navigate to voice call', async() => {
|
// TODO: test into a jitsi call
|
||||||
await waitFor(element(by.id('room-actions-voice'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
// it('should NOT navigate to voice call', async() => {
|
||||||
await element(by.id('room-actions-voice')).tap();
|
// await waitFor(element(by.id('room-actions-voice'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
||||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
// await element(by.id('room-actions-voice')).tap();
|
||||||
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
// await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
});
|
// await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
// });
|
||||||
|
|
||||||
it('should NOT navigate to video call', async() => {
|
// TODO: test into a jitsi call
|
||||||
await element(by.id('room-actions-video')).tap();
|
// it('should NOT navigate to video call', async() => {
|
||||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
// await element(by.id('room-actions-video')).tap();
|
||||||
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
// await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
});
|
// await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
// });
|
||||||
|
|
||||||
// TODO: test share room link
|
// TODO: test share room link
|
||||||
// it('should NOT navigate to share room', async() => {
|
// it('should NOT navigate to share room', async() => {
|
||||||
|
|
127
ios/Podfile.lock
127
ios/Podfile.lock
|
@ -5,7 +5,7 @@ PODS:
|
||||||
- React
|
- React
|
||||||
- BugsnagReactNative/Core (2.22.4):
|
- BugsnagReactNative/Core (2.22.4):
|
||||||
- React
|
- React
|
||||||
- Crashlytics (3.13.4):
|
- Crashlytics (3.14.0):
|
||||||
- Fabric (~> 1.10.2)
|
- Fabric (~> 1.10.2)
|
||||||
- DoubleConversion (1.1.6)
|
- DoubleConversion (1.1.6)
|
||||||
- EXAppLoaderProvider (6.0.0)
|
- EXAppLoaderProvider (6.0.0)
|
||||||
|
@ -26,24 +26,32 @@ PODS:
|
||||||
- EXWebBrowser (6.0.0):
|
- EXWebBrowser (6.0.0):
|
||||||
- UMCore
|
- UMCore
|
||||||
- Fabric (1.10.2)
|
- Fabric (1.10.2)
|
||||||
- Firebase/Core (6.5.0):
|
- Firebase/Core (6.8.1):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAnalytics (= 6.0.4)
|
- FirebaseAnalytics (= 6.1.1)
|
||||||
- Firebase/CoreOnly (6.5.0):
|
- Firebase/CoreOnly (6.8.1):
|
||||||
- FirebaseCore (= 6.1.0)
|
- FirebaseCore (= 6.2.3)
|
||||||
- FirebaseAnalytics (6.0.4):
|
- FirebaseAnalytics (6.1.1):
|
||||||
- FirebaseCore (~> 6.1)
|
- FirebaseCore (~> 6.2)
|
||||||
- FirebaseInstanceID (~> 4.2)
|
- FirebaseInstanceID (~> 4.2)
|
||||||
- GoogleAppMeasurement (= 6.0.4)
|
- GoogleAppMeasurement (= 6.1.1)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- GoogleUtilities/Network (~> 6.0)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||||
- nanopb (~> 0.3)
|
- nanopb (~> 0.3)
|
||||||
- FirebaseCore (6.1.0):
|
- FirebaseCore (6.2.3):
|
||||||
- GoogleUtilities/Environment (~> 6.0)
|
- FirebaseCoreDiagnostics (~> 1.0)
|
||||||
- GoogleUtilities/Logger (~> 6.0)
|
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
||||||
- FirebaseInstanceID (4.2.2):
|
- GoogleUtilities/Environment (~> 6.2)
|
||||||
|
- GoogleUtilities/Logger (~> 6.2)
|
||||||
|
- FirebaseCoreDiagnostics (1.0.1):
|
||||||
|
- FirebaseCoreDiagnosticsInterop (~> 1.0)
|
||||||
|
- GoogleDataTransportCCTSupport (~> 1.0)
|
||||||
|
- GoogleUtilities/Environment (~> 6.2)
|
||||||
|
- GoogleUtilities/Logger (~> 6.2)
|
||||||
|
- FirebaseCoreDiagnosticsInterop (1.0.0)
|
||||||
|
- FirebaseInstanceID (4.2.5):
|
||||||
- FirebaseCore (~> 6.0)
|
- FirebaseCore (~> 6.0)
|
||||||
- GoogleUtilities/Environment (~> 6.0)
|
- GoogleUtilities/Environment (~> 6.0)
|
||||||
- GoogleUtilities/UserDefaults (~> 6.0)
|
- GoogleUtilities/UserDefaults (~> 6.0)
|
||||||
|
@ -57,54 +65,43 @@ PODS:
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- glog
|
- glog
|
||||||
- glog (0.3.5)
|
- glog (0.3.5)
|
||||||
- GoogleAppMeasurement (6.0.4):
|
- GoogleAppMeasurement (6.1.1):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- GoogleUtilities/Network (~> 6.0)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||||
- nanopb (~> 0.3)
|
- nanopb (~> 0.3)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (6.2.3):
|
- GoogleDataTransport (1.2.0)
|
||||||
|
- GoogleDataTransportCCTSupport (1.0.4):
|
||||||
|
- GoogleDataTransport (~> 1.2)
|
||||||
|
- nanopb
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (6.3.0):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network
|
- GoogleUtilities/Network
|
||||||
- GoogleUtilities/Environment (6.2.3)
|
- GoogleUtilities/Environment (6.3.0)
|
||||||
- GoogleUtilities/Logger (6.2.3):
|
- GoogleUtilities/Logger (6.3.0):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/MethodSwizzler (6.2.3):
|
- GoogleUtilities/MethodSwizzler (6.3.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network (6.2.3):
|
- GoogleUtilities/Network (6.3.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
- GoogleUtilities/Reachability
|
- GoogleUtilities/Reachability
|
||||||
- "GoogleUtilities/NSData+zlib (6.2.3)"
|
- "GoogleUtilities/NSData+zlib (6.3.0)"
|
||||||
- GoogleUtilities/Reachability (6.2.3):
|
- GoogleUtilities/Reachability (6.3.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/UserDefaults (6.2.3):
|
- GoogleUtilities/UserDefaults (6.3.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- libwebp (1.0.2):
|
- libwebp (1.0.3):
|
||||||
- libwebp/core (= 1.0.2)
|
- libwebp/demux (= 1.0.3)
|
||||||
- libwebp/dec (= 1.0.2)
|
- libwebp/mux (= 1.0.3)
|
||||||
- libwebp/demux (= 1.0.2)
|
- libwebp/webp (= 1.0.3)
|
||||||
- libwebp/dsp (= 1.0.2)
|
- libwebp/demux (1.0.3):
|
||||||
- libwebp/enc (= 1.0.2)
|
|
||||||
- libwebp/mux (= 1.0.2)
|
|
||||||
- libwebp/utils (= 1.0.2)
|
|
||||||
- libwebp/webp (= 1.0.2)
|
|
||||||
- libwebp/core (1.0.2):
|
|
||||||
- libwebp/webp
|
- libwebp/webp
|
||||||
- libwebp/dec (1.0.2):
|
- libwebp/mux (1.0.3):
|
||||||
- libwebp/core
|
- libwebp/demux
|
||||||
- libwebp/demux (1.0.2):
|
- libwebp/webp (1.0.3)
|
||||||
- libwebp/core
|
|
||||||
- libwebp/dsp (1.0.2):
|
|
||||||
- libwebp/core
|
|
||||||
- libwebp/enc (1.0.2):
|
|
||||||
- libwebp/core
|
|
||||||
- libwebp/mux (1.0.2):
|
|
||||||
- libwebp/core
|
|
||||||
- libwebp/utils (1.0.2):
|
|
||||||
- libwebp/core
|
|
||||||
- libwebp/webp (1.0.2)
|
|
||||||
- nanopb (0.3.901):
|
- nanopb (0.3.901):
|
||||||
- nanopb/decode (= 0.3.901)
|
- nanopb/decode (= 0.3.901)
|
||||||
- nanopb/encode (= 0.3.901)
|
- nanopb/encode (= 0.3.901)
|
||||||
|
@ -157,6 +154,8 @@ PODS:
|
||||||
- React-cxxreact (= 0.60.4)
|
- React-cxxreact (= 0.60.4)
|
||||||
- React-jsi (= 0.60.4)
|
- React-jsi (= 0.60.4)
|
||||||
- React-jsinspector (0.60.4)
|
- React-jsinspector (0.60.4)
|
||||||
|
- react-native-background-timer (2.1.1):
|
||||||
|
- React
|
||||||
- react-native-document-picker (3.2.4):
|
- react-native-document-picker (3.2.4):
|
||||||
- React
|
- React
|
||||||
- react-native-keyboard-input (5.3.1):
|
- react-native-keyboard-input (5.3.1):
|
||||||
|
@ -239,10 +238,10 @@ PODS:
|
||||||
- RNVectorIcons (6.6.0):
|
- RNVectorIcons (6.6.0):
|
||||||
- React
|
- React
|
||||||
- RSKImageCropper (2.2.3)
|
- RSKImageCropper (2.2.3)
|
||||||
- SDWebImage (5.0.6):
|
- SDWebImage (5.1.1):
|
||||||
- SDWebImage/Core (= 5.0.6)
|
- SDWebImage/Core (= 5.1.1)
|
||||||
- SDWebImage/Core (5.0.6)
|
- SDWebImage/Core (5.1.1)
|
||||||
- SDWebImageWebPCoder (0.2.3):
|
- SDWebImageWebPCoder (0.2.4):
|
||||||
- libwebp (~> 1.0)
|
- libwebp (~> 1.0)
|
||||||
- SDWebImage/Core (~> 5.0)
|
- SDWebImage/Core (~> 5.0)
|
||||||
- UMBarCodeScannerInterface (3.0.0)
|
- UMBarCodeScannerInterface (3.0.0)
|
||||||
|
@ -282,6 +281,7 @@ DEPENDENCIES:
|
||||||
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
|
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
|
||||||
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||||
|
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
|
||||||
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
||||||
- react-native-keyboard-input (from `../node_modules/react-native-keyboard-input`)
|
- react-native-keyboard-input (from `../node_modules/react-native-keyboard-input`)
|
||||||
- react-native-keyboard-tracking-view (from `../node_modules/react-native-keyboard-tracking-view`)
|
- react-native-keyboard-tracking-view (from `../node_modules/react-native-keyboard-tracking-view`)
|
||||||
|
@ -335,8 +335,12 @@ SPEC REPOS:
|
||||||
- Firebase
|
- Firebase
|
||||||
- FirebaseAnalytics
|
- FirebaseAnalytics
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
|
- FirebaseCoreDiagnostics
|
||||||
|
- FirebaseCoreDiagnosticsInterop
|
||||||
- FirebaseInstanceID
|
- FirebaseInstanceID
|
||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
|
- GoogleDataTransport
|
||||||
|
- GoogleDataTransportCCTSupport
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
- libwebp
|
- libwebp
|
||||||
- nanopb
|
- nanopb
|
||||||
|
@ -391,6 +395,8 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
|
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
|
||||||
React-jsinspector:
|
React-jsinspector:
|
||||||
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
||||||
|
react-native-background-timer:
|
||||||
|
:path: "../node_modules/react-native-background-timer"
|
||||||
react-native-document-picker:
|
react-native-document-picker:
|
||||||
:path: "../node_modules/react-native-document-picker"
|
:path: "../node_modules/react-native-document-picker"
|
||||||
react-native-keyboard-input:
|
react-native-keyboard-input:
|
||||||
|
@ -495,7 +501,7 @@ EXTERNAL SOURCES:
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||||
BugsnagReactNative: 2114356c3acac0a71fb4b8962d3d1afdeb35f4d9
|
BugsnagReactNative: 2114356c3acac0a71fb4b8962d3d1afdeb35f4d9
|
||||||
Crashlytics: 2dfd686bcb918dc10ee0e76f7f853fe42c7bd552
|
Crashlytics: 540b7e5f5da5a042647227a5e3ac51d85eed06df
|
||||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||||
EXAppLoaderProvider: 7a8185228d8ba9e689a0e2d6d957fe9bdd49c8a0
|
EXAppLoaderProvider: 7a8185228d8ba9e689a0e2d6d957fe9bdd49c8a0
|
||||||
EXAV: 7228890721d1d74779bc3154fb678a44249b1c71
|
EXAV: 7228890721d1d74779bc3154fb678a44249b1c71
|
||||||
|
@ -505,15 +511,19 @@ SPEC CHECKSUMS:
|
||||||
EXPermissions: 99e52dc3e5f8e55153f1958004f6df2a30a1f2f5
|
EXPermissions: 99e52dc3e5f8e55153f1958004f6df2a30a1f2f5
|
||||||
EXWebBrowser: def838b95aa9d396f9ce71ace4e614ee16e7ee30
|
EXWebBrowser: def838b95aa9d396f9ce71ace4e614ee16e7ee30
|
||||||
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
||||||
Firebase: dedc9e48ea3f3649ad5f6b982f8a0c73508a14b5
|
Firebase: 9cbe4e5b5eaafa05dc932be58b7c8c3820d71e88
|
||||||
FirebaseAnalytics: 3fb375bc9d13779add4039716f868d233a473fad
|
FirebaseAnalytics: 843c7f64a8f9c79f0d03281197ebe7bb1d58d477
|
||||||
FirebaseCore: aecf02fb2274ec361b9bebeac112f5daa18273bd
|
FirebaseCore: e9d9bd1dae61c1e82bc1e0e617a9d832392086a0
|
||||||
FirebaseInstanceID: 662b8108a09fe9ed01aafdedba100fde8536b0f6
|
FirebaseCoreDiagnostics: 4c04ae09d0ab027c30179828c6bb47764df1bd13
|
||||||
|
FirebaseCoreDiagnosticsInterop: 6829da2b8d1fc795ff1bd99df751d3788035d2cb
|
||||||
|
FirebaseInstanceID: 550df9be1f99f751d8fcde3ac342a1e21a0e6c42
|
||||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||||
GoogleAppMeasurement: 183bd916af7f80deb67c01888368f1108d641832
|
GoogleAppMeasurement: 86a82f0e1f20b8eedf8e20326530138fd71409de
|
||||||
GoogleUtilities: d2b0e277a95962e09bb27f5cd42f5f0b6a506c7d
|
GoogleDataTransport: 8f9897b8e073687f24ca8d3c3a8013dec7d2d1cc
|
||||||
libwebp: b068a3bd7c45f7460f6715be7bed1a18fd5d6b48
|
GoogleDataTransportCCTSupport: 7455d07b98851aa63e4c05a34dad356ca588479e
|
||||||
|
GoogleUtilities: 9c2c544202301110b29f7974a82e77fdcf12bf51
|
||||||
|
libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e
|
||||||
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
|
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
|
||||||
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
|
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
|
||||||
React: ff7ee2ae5ee1c1d9ae2183b4111045b25294bb01
|
React: ff7ee2ae5ee1c1d9ae2183b4111045b25294bb01
|
||||||
|
@ -524,6 +534,7 @@ SPEC CHECKSUMS:
|
||||||
React-jsi: 21d3153b1153fbf6510a92b6b11e33e725cb7432
|
React-jsi: 21d3153b1153fbf6510a92b6b11e33e725cb7432
|
||||||
React-jsiexecutor: 7549641e48bafae7bfee3f3ea19bf4901639c5de
|
React-jsiexecutor: 7549641e48bafae7bfee3f3ea19bf4901639c5de
|
||||||
React-jsinspector: 73f24a02fa684ed6a2b828ba116874a2191ded88
|
React-jsinspector: 73f24a02fa684ed6a2b828ba116874a2191ded88
|
||||||
|
react-native-background-timer: 1b6e6b4e10f1b74c367a1fdc3c72b67c619b222b
|
||||||
react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061
|
react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061
|
||||||
react-native-keyboard-input: 2a01e0aceac330592bbe9b3101761bb9d8e6d1fb
|
react-native-keyboard-input: 2a01e0aceac330592bbe9b3101761bb9d8e6d1fb
|
||||||
react-native-keyboard-tracking-view: 1ebd24a2b6ca2314549aa51775995678094bffa1
|
react-native-keyboard-tracking-view: 1ebd24a2b6ca2314549aa51775995678094bffa1
|
||||||
|
@ -556,8 +567,8 @@ SPEC CHECKSUMS:
|
||||||
RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b
|
RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b
|
||||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||||
SDWebImage: 920f1a2ff1ca8296ad34f6e0510a1ef1d70ac965
|
SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8
|
||||||
SDWebImageWebPCoder: 7568737603c50f6237850afedd7e9e28e5917e6b
|
SDWebImageWebPCoder: cc72085bb20368b2f8dbb21b7e355c667e1309b7
|
||||||
UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
|
UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
|
||||||
UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
|
UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
|
||||||
UMConstantsInterface: 038bacb19de12b6fd328c589122c8dc977cccf61
|
UMConstantsInterface: 038bacb19de12b6fd328c589122c8dc977cccf61
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,9 +0,0 @@
|
||||||
framework module FirebaseCoreDiagnostics {
|
|
||||||
export *
|
|
||||||
module * { export * }
|
|
||||||
link "z"
|
|
||||||
link framework "Foundation"
|
|
||||||
link framework "Security"
|
|
||||||
link framework "SystemConfiguration"
|
|
||||||
link framework "UIKit"
|
|
||||||
}
|
|
|
@ -14,33 +14,45 @@
|
||||||
|
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#if __has_include(<UIKit/UIKit.h>)
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<AppKit/AppKit.h>)
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#import "FIRApp.h"
|
#import "FIRApp.h"
|
||||||
|
|
||||||
#import "Private/FIRAnalyticsConfiguration.h"
|
#import "Private/FIRAnalyticsConfiguration.h"
|
||||||
#import "Private/FIRAppInternal.h"
|
#import "Private/FIRAppInternal.h"
|
||||||
#import "Private/FIRBundleUtil.h"
|
#import "Private/FIRBundleUtil.h"
|
||||||
#import "Private/FIRComponentContainerInternal.h"
|
#import "Private/FIRComponentContainerInternal.h"
|
||||||
#import "Private/FIRConfigurationInternal.h"
|
#import "Private/FIRConfigurationInternal.h"
|
||||||
|
#import "Private/FIRCoreDiagnosticsConnector.h"
|
||||||
#import "Private/FIRLibrary.h"
|
#import "Private/FIRLibrary.h"
|
||||||
#import "Private/FIRLogger.h"
|
#import "Private/FIRLogger.h"
|
||||||
#import "Private/FIROptionsInternal.h"
|
#import "Private/FIROptionsInternal.h"
|
||||||
|
|
||||||
NSString *const kFIRServiceAdMob = @"AdMob";
|
// The kFIRService strings are only here while transitioning CoreDiagnostics from the Analytics
|
||||||
NSString *const kFIRServiceAuth = @"Auth";
|
// pod to a Core dependency. These symbols are not used and should be deleted after the transition.
|
||||||
NSString *const kFIRServiceAuthUI = @"AuthUI";
|
NSString *const kFIRServiceAdMob;
|
||||||
NSString *const kFIRServiceCrash = @"Crash";
|
NSString *const kFIRServiceAuth;
|
||||||
NSString *const kFIRServiceDatabase = @"Database";
|
NSString *const kFIRServiceAuthUI;
|
||||||
NSString *const kFIRServiceDynamicLinks = @"DynamicLinks";
|
NSString *const kFIRServiceCrash;
|
||||||
NSString *const kFIRServiceFirestore = @"Firestore";
|
NSString *const kFIRServiceDatabase;
|
||||||
NSString *const kFIRServiceFunctions = @"Functions";
|
NSString *const kFIRServiceDynamicLinks;
|
||||||
NSString *const kFIRServiceInstanceID = @"InstanceID";
|
NSString *const kFIRServiceFirestore;
|
||||||
NSString *const kFIRServiceInvites = @"Invites";
|
NSString *const kFIRServiceFunctions;
|
||||||
NSString *const kFIRServiceMessaging = @"Messaging";
|
NSString *const kFIRServiceInstanceID;
|
||||||
NSString *const kFIRServiceMeasurement = @"Measurement";
|
NSString *const kFIRServiceInvites;
|
||||||
NSString *const kFIRServicePerformance = @"Performance";
|
NSString *const kFIRServiceMessaging;
|
||||||
NSString *const kFIRServiceRemoteConfig = @"RemoteConfig";
|
NSString *const kFIRServiceMeasurement;
|
||||||
NSString *const kFIRServiceStorage = @"Storage";
|
NSString *const kFIRServicePerformance;
|
||||||
NSString *const kGGLServiceAnalytics = @"Analytics";
|
NSString *const kFIRServiceRemoteConfig;
|
||||||
NSString *const kGGLServiceSignIn = @"SignIn";
|
NSString *const kFIRServiceStorage;
|
||||||
|
NSString *const kGGLServiceAnalytics;
|
||||||
|
NSString *const kGGLServiceSignIn;
|
||||||
|
|
||||||
NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT";
|
NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT";
|
||||||
NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification";
|
NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification";
|
||||||
|
@ -103,19 +115,6 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
+ (void)configure {
|
+ (void)configure {
|
||||||
FIROptions *options = [FIROptions defaultOptions];
|
FIROptions *options = [FIROptions defaultOptions];
|
||||||
if (!options) {
|
if (!options) {
|
||||||
// Read the Info.plist to see if the flag is set. At this point we can't check any user defaults
|
|
||||||
// since the app isn't configured at all, so only rely on the Info.plist value.
|
|
||||||
NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist];
|
|
||||||
if (collectionEnabledPlistValue == nil || [collectionEnabledPlistValue boolValue]) {
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:kFIRAppDiagnosticsNotification
|
|
||||||
object:nil
|
|
||||||
userInfo:@{
|
|
||||||
kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore),
|
|
||||||
kFIRAppDiagnosticsErrorKey : [FIRApp errorForMissingOptions]
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
[NSException raise:kFirebaseCoreErrorDomain
|
[NSException raise:kFirebaseCoreErrorDomain
|
||||||
format:@"`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find "
|
format:@"`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find "
|
||||||
@"a valid GoogleService-Info.plist in your project. Please download one "
|
@"a valid GoogleService-Info.plist in your project. Please download one "
|
||||||
|
@ -290,30 +289,17 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)configureCore {
|
- (BOOL)configureCore {
|
||||||
[self checkExpectedBundleID];
|
[self checkExpectedBundleID];
|
||||||
if (![self isAppIDValid]) {
|
if (![self isAppIDValid]) {
|
||||||
if (_options.usingOptionsFromDefaultPlist && [self isDataCollectionDefaultEnabled]) {
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:kFIRAppDiagnosticsNotification
|
|
||||||
object:nil
|
|
||||||
userInfo:@{
|
|
||||||
kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore),
|
|
||||||
kFIRAppDiagnosticsErrorKey : [FIRApp errorForInvalidAppID],
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self isDataCollectionDefaultEnabled]) {
|
[self logCoreTelemetryIfEnabled];
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:kFIRAppDiagnosticsNotification
|
|
||||||
object:nil
|
|
||||||
userInfo:@{
|
|
||||||
kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore),
|
|
||||||
kFIRAppDiagnosticsFIRAppKey : self
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
// Initialize the Analytics once there is a valid options under default app. Analytics should
|
// Initialize the Analytics once there is a valid options under default app. Analytics should
|
||||||
|
@ -338,6 +324,8 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[self subscribeForAppDidBecomeActiveNotifications];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,26 +797,40 @@ static NSMutableDictionary *sLibraryVersions;
|
||||||
|
|
||||||
#pragma mark - Sending Logs
|
#pragma mark - Sending Logs
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
||||||
version:(NSString *)version
|
version:(NSString *)version
|
||||||
error:(NSError *)error {
|
error:(NSError *)error {
|
||||||
// If the user has manually turned off data collection, return and don't send logs.
|
// Do nothing. Please remove calls to this method.
|
||||||
if (![self isDataCollectionDefaultEnabled]) {
|
}
|
||||||
return;
|
#pragma clang diagnostic pop
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{
|
#pragma mark - App Life Cycle
|
||||||
kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeSDK),
|
|
||||||
kFIRAppDiagnosticsSDKNameKey : serviceName,
|
- (void)subscribeForAppDidBecomeActiveNotifications {
|
||||||
kFIRAppDiagnosticsSDKVersionKey : version,
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
kFIRAppDiagnosticsFIRAppKey : self
|
NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification;
|
||||||
}];
|
#endif
|
||||||
if (error) {
|
|
||||||
userInfo[kFIRAppDiagnosticsErrorKey] = error;
|
#if TARGET_OS_OSX
|
||||||
|
NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(appDidBecomeActive:)
|
||||||
|
name:notificationName
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appDidBecomeActive:(NSNotification *)notification {
|
||||||
|
[self logCoreTelemetryIfEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)logCoreTelemetryIfEnabled {
|
||||||
|
if ([self isDataCollectionDefaultEnabled]) {
|
||||||
|
[FIRCoreDiagnosticsConnector logCoreTelemetryWithOptions:_options];
|
||||||
}
|
}
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDiagnosticsNotification
|
|
||||||
object:nil
|
|
||||||
userInfo:userInfo];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface FIRComponentContainer ()
|
@interface FIRComponentContainer () {
|
||||||
|
dispatch_queue_t _containerQueue;
|
||||||
|
}
|
||||||
|
|
||||||
/// The dictionary of components that are registered for a particular app. The key is an NSString
|
/// The dictionary of components that are registered for a particular app. The key is an NSString
|
||||||
/// of the protocol.
|
/// of the protocol.
|
||||||
|
@ -67,6 +69,8 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
_app = app;
|
_app = app;
|
||||||
_cachedInstances = [NSMutableDictionary<NSString *, id> dictionary];
|
_cachedInstances = [NSMutableDictionary<NSString *, id> dictionary];
|
||||||
_components = [NSMutableDictionary<NSString *, FIRComponentCreationBlock> dictionary];
|
_components = [NSMutableDictionary<NSString *, FIRComponentCreationBlock> dictionary];
|
||||||
|
_containerQueue =
|
||||||
|
dispatch_queue_create("com.google.FirebaseComponentContainer", DISPATCH_QUEUE_SERIAL);
|
||||||
|
|
||||||
[self populateComponentsFromRegisteredClasses:allRegistrants forApp:app];
|
[self populateComponentsFromRegisteredClasses:allRegistrants forApp:app];
|
||||||
}
|
}
|
||||||
|
@ -92,7 +96,7 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
// Store the creation block for later usage.
|
// Store the creation block for later usage.
|
||||||
self.components[protocolName] = component.creationBlock;
|
self.components[protocolName] = component.creationBlock;
|
||||||
|
|
||||||
// Instantiate the
|
// Instantiate the instance if it has requested to be instantiated.
|
||||||
BOOL shouldInstantiateEager =
|
BOOL shouldInstantiateEager =
|
||||||
(component.instantiationTiming == FIRInstantiationTimingAlwaysEager);
|
(component.instantiationTiming == FIRInstantiationTimingAlwaysEager);
|
||||||
BOOL shouldInstantiateDefaultEager =
|
BOOL shouldInstantiateDefaultEager =
|
||||||
|
@ -136,7 +140,9 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
|
|
||||||
// The instance is ready to be returned, but check if it should be cached first before returning.
|
// The instance is ready to be returned, but check if it should be cached first before returning.
|
||||||
if (shouldCache) {
|
if (shouldCache) {
|
||||||
self.cachedInstances[protocolName] = instance;
|
dispatch_sync(_containerQueue, ^{
|
||||||
|
self.cachedInstances[protocolName] = instance;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
|
@ -147,7 +153,11 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
- (nullable id)instanceForProtocol:(Protocol *)protocol {
|
- (nullable id)instanceForProtocol:(Protocol *)protocol {
|
||||||
// Check if there is a cached instance, and return it if so.
|
// Check if there is a cached instance, and return it if so.
|
||||||
NSString *protocolName = NSStringFromProtocol(protocol);
|
NSString *protocolName = NSStringFromProtocol(protocol);
|
||||||
id cachedInstance = self.cachedInstances[protocolName];
|
__block id cachedInstance;
|
||||||
|
dispatch_sync(_containerQueue, ^{
|
||||||
|
cachedInstance = self.cachedInstances[protocolName];
|
||||||
|
});
|
||||||
|
|
||||||
if (cachedInstance) {
|
if (cachedInstance) {
|
||||||
return cachedInstance;
|
return cachedInstance;
|
||||||
}
|
}
|
||||||
|
@ -161,14 +171,29 @@ static NSMutableSet<Class> *sFIRComponentRegistrants;
|
||||||
|
|
||||||
- (void)removeAllCachedInstances {
|
- (void)removeAllCachedInstances {
|
||||||
// Loop through the cache and notify each instance that is a maintainer to clean up after itself.
|
// Loop through the cache and notify each instance that is a maintainer to clean up after itself.
|
||||||
for (id instance in self.cachedInstances.allValues) {
|
// Design note: we're getting a copy here, unlocking the cached instances, iterating over the
|
||||||
|
// copy, then locking and removing all cached instances. A race condition *could* exist where a
|
||||||
|
// new cached instance is created between the copy and the removal, but the chances are slim and
|
||||||
|
// side-effects are significantly smaller than including the entire loop in the `dispatch_sync`
|
||||||
|
// block (access to the cache from inside the block would deadlock and crash).
|
||||||
|
__block NSDictionary<NSString *, id> *instancesCopy;
|
||||||
|
dispatch_sync(_containerQueue, ^{
|
||||||
|
instancesCopy = [self.cachedInstances copy];
|
||||||
|
});
|
||||||
|
|
||||||
|
for (id instance in instancesCopy.allValues) {
|
||||||
if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] &&
|
if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] &&
|
||||||
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
[instance respondsToSelector:@selector(appWillBeDeleted:)]) {
|
||||||
[instance appWillBeDeleted:self.app];
|
[instance appWillBeDeleted:self.app];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.cachedInstances removeAllObjects];
|
instancesCopy = nil;
|
||||||
|
|
||||||
|
// Empty the cache.
|
||||||
|
dispatch_sync(_containerQueue, ^{
|
||||||
|
[self.cachedInstances removeAllObjects];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "Private/FIRCoreDiagnosticsConnector.h"
|
||||||
|
|
||||||
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsInterop.h>
|
||||||
|
|
||||||
|
#import <FirebaseCore/FIROptions.h>
|
||||||
|
|
||||||
|
#import "Private/FIRAppInternal.h"
|
||||||
|
#import "Private/FIRDiagnosticsData.h"
|
||||||
|
#import "Private/FIROptionsInternal.h"
|
||||||
|
|
||||||
|
// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop.
|
||||||
|
Class<FIRCoreDiagnosticsInterop> FIRCoreDiagnosticsImplementation;
|
||||||
|
|
||||||
|
@implementation FIRCoreDiagnosticsConnector
|
||||||
|
|
||||||
|
+ (void)initialize {
|
||||||
|
if (!FIRCoreDiagnosticsImplementation) {
|
||||||
|
FIRCoreDiagnosticsImplementation = NSClassFromString(@"FIRCoreDiagnostics");
|
||||||
|
if (FIRCoreDiagnosticsImplementation) {
|
||||||
|
NSAssert([FIRCoreDiagnosticsImplementation
|
||||||
|
conformsToProtocol:@protocol(FIRCoreDiagnosticsInterop)],
|
||||||
|
@"If FIRCoreDiagnostics is implemented, it must conform to the interop protocol.");
|
||||||
|
NSAssert(
|
||||||
|
[FIRCoreDiagnosticsImplementation respondsToSelector:@selector(sendDiagnosticsData:)],
|
||||||
|
@"If FIRCoreDiagnostics is implemented, it must implement +sendDiagnosticsData.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logCoreTelemetryWithOptions:(FIROptions *)options {
|
||||||
|
if (FIRCoreDiagnosticsImplementation) {
|
||||||
|
FIRDiagnosticsData *diagnosticsData = [[FIRDiagnosticsData alloc] init];
|
||||||
|
[diagnosticsData insertValue:@(YES) forKey:kFIRCDIsDataCollectionDefaultEnabledKey];
|
||||||
|
[diagnosticsData insertValue:[FIRApp firebaseUserAgent] forKey:kFIRCDFirebaseUserAgentKey];
|
||||||
|
[diagnosticsData insertValue:@(FIRConfigTypeCore) forKey:kFIRCDConfigurationTypeKey];
|
||||||
|
[diagnosticsData insertValue:options.googleAppID forKey:kFIRCDGoogleAppIDKey];
|
||||||
|
[diagnosticsData insertValue:options.bundleID forKey:kFIRCDBundleIDKey];
|
||||||
|
[diagnosticsData insertValue:@(options.usingOptionsFromDefaultPlist)
|
||||||
|
forKey:kFIRCDUsingOptionsFromDefaultPlistKey];
|
||||||
|
[diagnosticsData insertValue:options.libraryVersionID forKey:kFIRCDLibraryVersionIDKey];
|
||||||
|
[FIRCoreDiagnosticsImplementation sendDiagnosticsData:diagnosticsData];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "Private/FIRDiagnosticsData.h"
|
||||||
|
|
||||||
|
#import <FirebaseCore/FIRApp.h>
|
||||||
|
|
||||||
|
#import "Private/FIRAppInternal.h"
|
||||||
|
#import "Private/FIROptionsInternal.h"
|
||||||
|
|
||||||
|
@implementation FIRDiagnosticsData {
|
||||||
|
/** Backing ivar for the diagnosticObjects property. */
|
||||||
|
NSMutableDictionary<NSString *, id> *_diagnosticObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_diagnosticObjects = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertValue:(nullable id)value forKey:(NSString *)key {
|
||||||
|
if (key) {
|
||||||
|
_diagnosticObjects[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - FIRCoreDiagnosticsData
|
||||||
|
|
||||||
|
- (NSDictionary<NSString *, id> *)diagnosticObjects {
|
||||||
|
if (!_diagnosticObjects[kFIRCDllAppsCountKey]) {
|
||||||
|
_diagnosticObjects[kFIRCDllAppsCountKey] = @([FIRApp allApps].count);
|
||||||
|
}
|
||||||
|
if (!_diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]) {
|
||||||
|
_diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey] =
|
||||||
|
@([[FIRApp defaultApp] isDataCollectionDefaultEnabled]);
|
||||||
|
}
|
||||||
|
if (!_diagnosticObjects[kFIRCDFirebaseUserAgentKey]) {
|
||||||
|
_diagnosticObjects[kFIRCDFirebaseUserAgentKey] = [FIRApp firebaseUserAgent];
|
||||||
|
}
|
||||||
|
return _diagnosticObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
|
- (void)setDiagnosticObjects:(NSDictionary<NSString *, id> *)diagnosticObjects {
|
||||||
|
NSAssert(NO, @"Please use -insertValue:forKey:");
|
||||||
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
@end
|
|
@ -34,26 +34,6 @@ typedef NS_ENUM(NSInteger, FIRConfigType) {
|
||||||
FIRConfigTypeSDK = 2,
|
FIRConfigTypeSDK = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Names of services provided by Firebase.
|
|
||||||
*/
|
|
||||||
extern NSString *const kFIRServiceAdMob;
|
|
||||||
extern NSString *const kFIRServiceAuth;
|
|
||||||
extern NSString *const kFIRServiceAuthUI;
|
|
||||||
extern NSString *const kFIRServiceDatabase;
|
|
||||||
extern NSString *const kFIRServiceDynamicLinks;
|
|
||||||
extern NSString *const kFIRServiceInstanceID;
|
|
||||||
extern NSString *const kFIRServiceMessaging;
|
|
||||||
extern NSString *const kFIRServiceMeasurement;
|
|
||||||
extern NSString *const kFIRServiceRemoteConfig;
|
|
||||||
extern NSString *const kFIRServiceStorage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Names of services provided by the Google pod, but logged by the Firebase pod.
|
|
||||||
*/
|
|
||||||
extern NSString *const kGGLServiceAnalytics;
|
|
||||||
extern NSString *const kGGLServiceSignIn;
|
|
||||||
|
|
||||||
extern NSString *const kFIRDefaultAppName;
|
extern NSString *const kFIRDefaultAppName;
|
||||||
extern NSString *const kFIRAppReadyToConfigureSDKNotification;
|
extern NSString *const kFIRAppReadyToConfigureSDKNotification;
|
||||||
extern NSString *const kFIRAppDeleteNotification;
|
extern NSString *const kFIRAppDeleteNotification;
|
||||||
|
@ -160,6 +140,8 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by each SDK to send logs about SDK configuration status to Clearcut.
|
* Used by each SDK to send logs about SDK configuration status to Clearcut.
|
||||||
|
*
|
||||||
|
* @note This API is a no-op, please remove calls to it.
|
||||||
*/
|
*/
|
||||||
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
||||||
version:(NSString *)version
|
version:(NSString *)version
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@class FIRDiagnosticsData;
|
||||||
|
@class FIROptions;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** Connects FIRCore with the CoreDiagnostics library. */
|
||||||
|
@interface FIRCoreDiagnosticsConnector : NSObject
|
||||||
|
|
||||||
|
/** Logs FirebaseCore related data.
|
||||||
|
*
|
||||||
|
* @param options The options object containing data to log.
|
||||||
|
*/
|
||||||
|
+ (void)logCoreTelemetryWithOptions:(FIROptions *)options;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsData.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** Implements the FIRCoreDiagnosticsData protocol to log diagnostics data. */
|
||||||
|
@interface FIRDiagnosticsData : NSObject <FIRCoreDiagnosticsData>
|
||||||
|
|
||||||
|
/** Inserts values into the diagnosticObjects dictionary if the value isn't nil.
|
||||||
|
*
|
||||||
|
* @param value The value to insert if it's not nil.
|
||||||
|
* @param key The key to associate it with.
|
||||||
|
*/
|
||||||
|
- (void)insertValue:(nullable id)value forKey:(NSString *)key;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -1,8 +1,8 @@
|
||||||
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||||
|
|
||||||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
The repository also includes GoogleUtilities source. The
|
||||||
|
@ -80,9 +80,8 @@ For the pod that you want to develop:
|
||||||
|
|
||||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||||
|
|
||||||
Firestore and Functions have self contained Xcode projects. See
|
Firestore has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md) and
|
[Firestore/README.md](Firestore/README.md).
|
||||||
[Functions/README.md](Functions/README.md).
|
|
||||||
|
|
||||||
### Adding a New Firebase Pod
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
|
@ -179,7 +178,8 @@ very grateful! We'd like to empower as many developers as we can to be able to
|
||||||
participate in the Firebase community.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### macOS and tvOS
|
### macOS and tvOS
|
||||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||||
|
FirebaseDatabase, FirebaseMessaging,
|
||||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||||
macOS and tvOS.
|
macOS and tvOS.
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ Note that the Firebase pod is not available for macOS and tvOS.
|
||||||
To install, add a subset of the following to the Podfile:
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
pod 'FirebaseABTesting'
|
||||||
pod 'FirebaseAuth'
|
pod 'FirebaseAuth'
|
||||||
pod 'FirebaseCore'
|
pod 'FirebaseCore'
|
||||||
pod 'FirebaseDatabase'
|
pod 'FirebaseDatabase'
|
||||||
|
|
674
ios/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m
generated
Normal file
674
ios/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m
generated
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
#import <GoogleDataTransport/GDTEvent.h>
|
||||||
|
#import <GoogleDataTransport/GDTTargets.h>
|
||||||
|
#import <GoogleDataTransport/GDTTransport.h>
|
||||||
|
|
||||||
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
#import <GoogleUtilities/GULLogger.h>
|
||||||
|
|
||||||
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsData.h>
|
||||||
|
#import <FirebaseCoreDiagnosticsInterop/FIRCoreDiagnosticsInterop.h>
|
||||||
|
|
||||||
|
#import <nanopb/pb.h>
|
||||||
|
#import <nanopb/pb_decode.h>
|
||||||
|
#import <nanopb/pb_encode.h>
|
||||||
|
|
||||||
|
#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
||||||
|
|
||||||
|
#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h"
|
||||||
|
|
||||||
|
/** The logger service string to use when printing to the console. */
|
||||||
|
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
||||||
|
|
||||||
|
#ifdef FIREBASE_BUILD_ZIP_FILE
|
||||||
|
static BOOL kUsingZipFile = YES;
|
||||||
|
#else // FIREBASE_BUILD_ZIP_FILE
|
||||||
|
static BOOL kUsingZipFile = NO;
|
||||||
|
#endif // FIREBASE_BUILD_ZIP_FILE
|
||||||
|
|
||||||
|
#ifdef FIREBASE_BUILD_CARTHAGE
|
||||||
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE
|
||||||
|
#elif FIREBASE_BUILD_ZIP_FILE
|
||||||
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE
|
||||||
|
#else
|
||||||
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceAutoML = @"MLVisionOnDeviceAutoML";
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceFace = @"MLVisionOnDeviceFace";
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceBarcode = @"MLVisionOnDeviceBarcode";
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceText = @"MLVisionOnDeviceText";
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceLabel = @"MLVisionOnDeviceLabel";
|
||||||
|
static NSString *const kFIRServiceMLVisionOnDeviceObjectDetection =
|
||||||
|
@"MLVisionOnDeviceObjectDetection";
|
||||||
|
static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter";
|
||||||
|
|
||||||
|
static NSString *const kFIRServiceAdMob = @"AdMob";
|
||||||
|
static NSString *const kFIRServiceAuth = @"Auth";
|
||||||
|
static NSString *const kFIRServiceAuthUI = @"AuthUI";
|
||||||
|
static NSString *const kFIRServiceCrash = @"Crash";
|
||||||
|
static NSString *const kFIRServiceDatabase = @"Database";
|
||||||
|
static NSString *const kFIRServiceDynamicLinks = @"DynamicLinks";
|
||||||
|
static NSString *const kFIRServiceFirestore = @"Firestore";
|
||||||
|
static NSString *const kFIRServiceFunctions = @"Functions";
|
||||||
|
static NSString *const kFIRServiceIAM = @"InAppMessaging";
|
||||||
|
static NSString *const kFIRServiceInstanceID = @"InstanceID";
|
||||||
|
static NSString *const kFIRServiceInvites = @"Invites";
|
||||||
|
static NSString *const kFIRServiceMessaging = @"Messaging";
|
||||||
|
static NSString *const kFIRServiceMeasurement = @"Measurement";
|
||||||
|
static NSString *const kFIRServicePerformance = @"Performance";
|
||||||
|
static NSString *const kFIRServiceRemoteConfig = @"RemoteConfig";
|
||||||
|
static NSString *const kFIRServiceStorage = @"Storage";
|
||||||
|
static NSString *const kGGLServiceAnalytics = @"Analytics";
|
||||||
|
static NSString *const kGGLServiceSignIn = @"SignIn";
|
||||||
|
static NSString *const kFIRAppDiagnosticsConfigurationTypeKey =
|
||||||
|
@"FIRAppDiagnosticsConfigurationTypeKey";
|
||||||
|
static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey";
|
||||||
|
static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey";
|
||||||
|
static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file name to the recent heartbeat date.
|
||||||
|
*/
|
||||||
|
NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note This should implement the GDTEventDataObject protocol, but can't because of weak-linking.
|
||||||
|
*/
|
||||||
|
@interface FIRCoreDiagnosticsLog : NSObject
|
||||||
|
|
||||||
|
/** The config that will be converted to proto bytes. */
|
||||||
|
@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FIRCoreDiagnosticsLog
|
||||||
|
|
||||||
|
- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provided and required by the GDTEventDataObject protocol.
|
||||||
|
- (NSData *)transportBytes {
|
||||||
|
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
||||||
|
|
||||||
|
// Encode 1 time to determine the size.
|
||||||
|
if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||||
|
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for size: %s",
|
||||||
|
PB_GET_ERROR(&sizestream));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode a 2nd time to actually get the bytes from it.
|
||||||
|
size_t bufferSize = sizestream.bytes_written;
|
||||||
|
CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
|
||||||
|
pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
|
||||||
|
if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
|
||||||
|
GDTLogError(GDTMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
|
||||||
|
PB_GET_ERROR(&ostream));
|
||||||
|
}
|
||||||
|
CFDataSetLength(dataRef, ostream.bytes_written);
|
||||||
|
|
||||||
|
return CFBridgingRelease(dataRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
pb_release(logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** This class produces a protobuf containing diagnostics and usage data to be logged. */
|
||||||
|
@interface FIRCoreDiagnostics : NSObject <FIRCoreDiagnosticsInterop>
|
||||||
|
|
||||||
|
/** The queue on which all diagnostics collection will occur. */
|
||||||
|
@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue;
|
||||||
|
|
||||||
|
/** The transport object used to send data. */
|
||||||
|
@property(nonatomic, readonly) GDTTransport *transport;
|
||||||
|
|
||||||
|
/** The storage to store the date of the last sent heartbeat. */
|
||||||
|
@property(nonatomic, readonly) FIRCoreDiagnosticsDateFileStorage *heartbeatDateStorage;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
@implementation FIRCoreDiagnostics
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static FIRCoreDiagnostics *sharedInstance;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedInstance = [[FIRCoreDiagnostics alloc] init];
|
||||||
|
});
|
||||||
|
return sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
GDTTransport *transport = [[GDTTransport alloc] initWithMappingID:@"137"
|
||||||
|
transformers:nil
|
||||||
|
target:kGDTTargetCCT];
|
||||||
|
|
||||||
|
FIRCoreDiagnosticsDateFileStorage *dateStorage = [[FIRCoreDiagnosticsDateFileStorage alloc]
|
||||||
|
initWithFileURL:[[self class] filePathURLWithName:kFIRCoreDiagnosticsHeartbeatDateFileName]];
|
||||||
|
|
||||||
|
return [self initWithTransport:transport heartbeatDateStorage:dateStorage];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializer for unit tests.
|
||||||
|
*
|
||||||
|
* @param transport A `GDTTransport` instance which that be used to send event.
|
||||||
|
* @param heartbeatDateStorage An instanse of date storage to track heartbeat sending.
|
||||||
|
* @return Returns the initialized `FIRCoreDiagnostics` instance.
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithTransport:(GDTTransport *)transport
|
||||||
|
heartbeatDateStorage:(FIRCoreDiagnosticsDateFileStorage *)heartbeatDateStorage {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_diagnosticsQueue =
|
||||||
|
dispatch_queue_create("com.google.FIRCoreDiagnostics", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_transport = transport;
|
||||||
|
_heartbeatDateStorage = heartbeatDateStorage;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - File path helpers
|
||||||
|
|
||||||
|
/** Returns the URL path of the file with name fileName under the Application Support folder for
|
||||||
|
* local logging. Creates the Application Support folder if the folder doesn't exist.
|
||||||
|
*
|
||||||
|
* @return the URL path of the file with the name fileName in Application Support.
|
||||||
|
*/
|
||||||
|
+ (NSURL *)filePathURLWithName:(NSString *)fileName {
|
||||||
|
@synchronized(self) {
|
||||||
|
NSArray<NSString *> *paths =
|
||||||
|
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||||
|
NSArray<NSString *> *components = @[ paths.lastObject, @"Google/FIRApp" ];
|
||||||
|
NSString *directoryString = [NSString pathWithComponents:components];
|
||||||
|
NSURL *directoryURL = [NSURL fileURLWithPath:directoryString];
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
if (![directoryURL checkResourceIsReachableAndReturnError:&error]) {
|
||||||
|
// If fail creating the Application Support directory, return nil.
|
||||||
|
if (![[NSFileManager defaultManager] createDirectoryAtURL:directoryURL
|
||||||
|
withIntermediateDirectories:YES
|
||||||
|
attributes:nil
|
||||||
|
error:&error]) {
|
||||||
|
GULLogWarning(kFIRCoreDiagnostics, YES, @"I-COR100001",
|
||||||
|
@"Unable to create internal state storage: %@", error);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [directoryURL URLByAppendingPathComponent:fileName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Metadata helpers
|
||||||
|
|
||||||
|
/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus,
|
||||||
|
* @"iPhone7,2" for iPhone 6, etc. Refer to the Hardware strings at
|
||||||
|
* https://en.wikipedia.org/wiki/List_of_iOS_devices
|
||||||
|
*
|
||||||
|
* @return The device model as an NSString.
|
||||||
|
*/
|
||||||
|
+ (NSString *)deviceModel {
|
||||||
|
static NSString *deviceModel = nil;
|
||||||
|
if (deviceModel == nil) {
|
||||||
|
struct utsname systemInfo;
|
||||||
|
uname(&systemInfo);
|
||||||
|
deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
return deviceModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - nanopb helper functions
|
||||||
|
|
||||||
|
/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
|
||||||
|
*
|
||||||
|
* @note Memory needs to be free manually, through pb_free or pb_release.
|
||||||
|
* @param string The string to encode as pb_bytes.
|
||||||
|
*/
|
||||||
|
pb_bytes_array_t *FIREncodeString(NSString *string) {
|
||||||
|
NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
return FIREncodeData(stringBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array.
|
||||||
|
*
|
||||||
|
* @note Memory needs to be free manually, through pb_free or pb_release.
|
||||||
|
* @param data The data to copy into the new bytes array.
|
||||||
|
*/
|
||||||
|
pb_bytes_array_t *FIREncodeData(NSData *data) {
|
||||||
|
pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
|
||||||
|
memcpy(pbBytes->bytes, [data bytes], data.length);
|
||||||
|
pbBytes->size = (pb_size_t)data.length;
|
||||||
|
return pbBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Maps a service string to the representative nanopb enum.
|
||||||
|
*
|
||||||
|
* @param serviceString The SDK service string to convert.
|
||||||
|
* @return The representative nanopb enum.
|
||||||
|
*/
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum(
|
||||||
|
NSString *serviceString) {
|
||||||
|
static NSDictionary<NSString *, NSNumber *> *serviceStringToTypeEnum;
|
||||||
|
if (serviceStringToTypeEnum == nil) {
|
||||||
|
serviceStringToTypeEnum = @{
|
||||||
|
kFIRServiceAdMob : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB),
|
||||||
|
kFIRServiceMessaging : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING),
|
||||||
|
kFIRServiceMeasurement :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT),
|
||||||
|
kFIRServiceRemoteConfig :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG),
|
||||||
|
kFIRServiceDatabase : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE),
|
||||||
|
kFIRServiceDynamicLinks :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS),
|
||||||
|
kFIRServiceAuth : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH),
|
||||||
|
kFIRServiceAuthUI : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI),
|
||||||
|
kFIRServiceFirestore : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE),
|
||||||
|
kFIRServiceFunctions : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS),
|
||||||
|
kFIRServicePerformance :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE),
|
||||||
|
kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE),
|
||||||
|
kFIRServiceMLVisionOnDeviceAutoML :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML),
|
||||||
|
kFIRServiceMLVisionOnDeviceFace :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE),
|
||||||
|
kFIRServiceMLVisionOnDeviceBarcode :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE),
|
||||||
|
kFIRServiceMLVisionOnDeviceText :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT),
|
||||||
|
kFIRServiceMLVisionOnDeviceLabel :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL),
|
||||||
|
kFIRServiceMLVisionOnDeviceObjectDetection : @(
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION),
|
||||||
|
kFIRServiceMLModelInterpreter :
|
||||||
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER),
|
||||||
|
kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS),
|
||||||
|
kGGLServiceSignIn : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN),
|
||||||
|
kFIRServiceIAM : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (serviceStringToTypeEnum[serviceString] != nil) {
|
||||||
|
return (int32_t)serviceStringToTypeEnum[serviceString].longLongValue;
|
||||||
|
}
|
||||||
|
return logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Proto population functions
|
||||||
|
|
||||||
|
/** Populates the given proto with data related to an SDK logDiagnostics call from the
|
||||||
|
* diagnosticObjects dictionary.
|
||||||
|
*
|
||||||
|
* @param config The proto to populate
|
||||||
|
* @param diagnosticObjects The dictionary of diagnostics objects.
|
||||||
|
*/
|
||||||
|
void FIRPopulateProtoWithInfoFromUserInfoParams(logs_proto_mobilesdk_ios_ICoreConfiguration *config,
|
||||||
|
NSDictionary<NSString *, id> *diagnosticObjects) {
|
||||||
|
NSNumber *configurationType = diagnosticObjects[kFIRCDConfigurationTypeKey];
|
||||||
|
if (configurationType != nil) {
|
||||||
|
switch (configurationType.integerValue) {
|
||||||
|
case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE:
|
||||||
|
config->configuration_type =
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE;
|
||||||
|
config->has_configuration_type = 1;
|
||||||
|
break;
|
||||||
|
case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK:
|
||||||
|
config->configuration_type =
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK;
|
||||||
|
config->has_configuration_type = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *sdkName = diagnosticObjects[kFIRCDSdkNameKey];
|
||||||
|
if (sdkName) {
|
||||||
|
config->sdk_name = FIRMapFromServiceStringToTypeEnum(sdkName);
|
||||||
|
config->has_sdk_name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *version = diagnosticObjects[kFIRCDSdkVersionKey];
|
||||||
|
if (version) {
|
||||||
|
config->sdk_version = FIREncodeString(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates the given proto with data from the calling FIRApp using the given
|
||||||
|
* diagnosticObjects dictionary.
|
||||||
|
*
|
||||||
|
* @param config The proto to populate
|
||||||
|
* @param diagnosticObjects The dictionary of diagnostics objects.
|
||||||
|
*/
|
||||||
|
void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfiguration *config,
|
||||||
|
NSDictionary<NSString *, id> *diagnosticObjects) {
|
||||||
|
config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE;
|
||||||
|
config->has_pod_name = 1;
|
||||||
|
|
||||||
|
if (!diagnosticObjects[kFIRCDllAppsCountKey]) {
|
||||||
|
GDTLogError(GDTMCEGeneralError, @"%@", @"App count is a required value in the data dict.");
|
||||||
|
}
|
||||||
|
config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue];
|
||||||
|
config->has_app_count = 1;
|
||||||
|
|
||||||
|
NSString *googleAppID = diagnosticObjects[kFIRCDGoogleAppIDKey];
|
||||||
|
if (googleAppID.length) {
|
||||||
|
config->app_id = FIREncodeString(googleAppID);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *bundleID = diagnosticObjects[kFIRCDBundleIDKey];
|
||||||
|
if (bundleID.length) {
|
||||||
|
config->bundle_id = FIREncodeString(bundleID);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *firebaseUserAgent = diagnosticObjects[kFIRCDFirebaseUserAgentKey];
|
||||||
|
if (firebaseUserAgent.length) {
|
||||||
|
config->platform_info = FIREncodeString(firebaseUserAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSNumber *usingOptionsFromDefaultPlist = diagnosticObjects[kFIRCDUsingOptionsFromDefaultPlistKey];
|
||||||
|
if (usingOptionsFromDefaultPlist != nil) {
|
||||||
|
config->use_default_app = [usingOptionsFromDefaultPlist boolValue];
|
||||||
|
config->has_use_default_app = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *libraryVersionID = diagnosticObjects[kFIRCDLibraryVersionIDKey];
|
||||||
|
if (libraryVersionID) {
|
||||||
|
config->icore_version = FIREncodeString(libraryVersionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *deviceModel = [FIRCoreDiagnostics deviceModel];
|
||||||
|
if (deviceModel.length) {
|
||||||
|
config->device_model = FIREncodeString(deviceModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *osVersion = [GULAppEnvironmentUtil systemVersion];
|
||||||
|
if (osVersion.length) {
|
||||||
|
config->os_version = FIREncodeString(osVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
config->using_zip_file = kUsingZipFile;
|
||||||
|
config->has_using_zip_file = 1;
|
||||||
|
config->deployment_type = kDeploymentType;
|
||||||
|
config->has_deployment_type = 1;
|
||||||
|
config->deployed_in_app_store = [GULAppEnvironmentUtil isFromAppStore];
|
||||||
|
config->has_deployed_in_app_store = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates the given proto with installed services data.
|
||||||
|
*
|
||||||
|
* @param config The proto to populate
|
||||||
|
*/
|
||||||
|
void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
|
||||||
|
NSMutableArray<NSNumber *> *sdkServiceInstalledArray = [NSMutableArray array];
|
||||||
|
|
||||||
|
// AdMob
|
||||||
|
if (NSClassFromString(@"GADBannerView") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAdMob))];
|
||||||
|
}
|
||||||
|
// CloudMessaging
|
||||||
|
if (NSClassFromString(@"FIRMessaging") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMessaging))];
|
||||||
|
}
|
||||||
|
// RemoteConfig
|
||||||
|
if (NSClassFromString(@"FIRRemoteConfig") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceRemoteConfig))];
|
||||||
|
}
|
||||||
|
// Measurement/Analtyics
|
||||||
|
if (NSClassFromString(@"FIRAnalytics") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device AutoML.
|
||||||
|
if (NSClassFromString(@"FIRVisionOnDeviceAutoMLImageLabelerOptions") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceAutoML))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device Face.
|
||||||
|
if (NSClassFromString(@"FIRVisionFaceDetector") != nil &&
|
||||||
|
NSClassFromString(@"GMVFaceDetector") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceFace))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device Barcode.
|
||||||
|
if (NSClassFromString(@"FIRVisionBarcodeDetector") != nil &&
|
||||||
|
NSClassFromString(@"GMVBarcodeDetector") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceBarcode))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device Text.
|
||||||
|
if (NSClassFromString(@"FIRVisionTextDetector") != nil &&
|
||||||
|
NSClassFromString(@"GMVTextDetector") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceText))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device Image Label.
|
||||||
|
if (NSClassFromString(@"FIRVisionLabelDetector") != nil &&
|
||||||
|
NSClassFromString(@"GMVLabelDetector") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceLabel))];
|
||||||
|
}
|
||||||
|
// ML Vision On Device Object.
|
||||||
|
if (NSClassFromString(@"FIRVisionObjectDetector") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceObjectDetection))];
|
||||||
|
}
|
||||||
|
// ML Model Interpreter
|
||||||
|
if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLModelInterpreter))];
|
||||||
|
}
|
||||||
|
// Database
|
||||||
|
if (NSClassFromString(@"FIRDatabase") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDatabase))];
|
||||||
|
}
|
||||||
|
// DynamicDeepLink
|
||||||
|
if (NSClassFromString(@"FIRDynamicLinks") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDynamicLinks))];
|
||||||
|
}
|
||||||
|
// Auth
|
||||||
|
if (NSClassFromString(@"FIRAuth") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuth))];
|
||||||
|
}
|
||||||
|
// AuthUI
|
||||||
|
if (NSClassFromString(@"FUIAuth") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuthUI))];
|
||||||
|
}
|
||||||
|
// Firestore
|
||||||
|
if (NSClassFromString(@"FIRFirestore") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFirestore))];
|
||||||
|
}
|
||||||
|
// Functions
|
||||||
|
if (NSClassFromString(@"FIRFunctions") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFunctions))];
|
||||||
|
}
|
||||||
|
// Performance
|
||||||
|
if (NSClassFromString(@"FIRPerformance") != nil) {
|
||||||
|
[sdkServiceInstalledArray
|
||||||
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServicePerformance))];
|
||||||
|
}
|
||||||
|
// Storage
|
||||||
|
if (NSClassFromString(@"FIRStorage") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceStorage))];
|
||||||
|
}
|
||||||
|
// SignIn via Google pod
|
||||||
|
if (NSClassFromString(@"GIDSignIn") != nil && NSClassFromString(@"GGLContext") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceSignIn))];
|
||||||
|
}
|
||||||
|
// Analytics via Google pod
|
||||||
|
if (NSClassFromString(@"GAI") != nil && NSClassFromString(@"GGLContext") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceAnalytics))];
|
||||||
|
}
|
||||||
|
|
||||||
|
// In-App Messaging
|
||||||
|
if (NSClassFromString(@"FIRInAppMessaging") != nil) {
|
||||||
|
[sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceIAM))];
|
||||||
|
}
|
||||||
|
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *servicesInstalled =
|
||||||
|
malloc(sizeof(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType) *
|
||||||
|
sdkServiceInstalledArray.count);
|
||||||
|
for (NSUInteger i = 0; i < sdkServiceInstalledArray.count; i++) {
|
||||||
|
NSNumber *typeEnum = sdkServiceInstalledArray[i];
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType serviceType =
|
||||||
|
(int32_t)typeEnum.integerValue;
|
||||||
|
servicesInstalled[i] = serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->sdk_service_installed = servicesInstalled;
|
||||||
|
config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates the proto with the number of linked frameworks.
|
||||||
|
*
|
||||||
|
* @param config The proto to populate.
|
||||||
|
*/
|
||||||
|
void FIRPopulateProtoWithNumberOfLinkedFrameworks(
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
|
||||||
|
int numFrameworks = -1; // Subtract the app binary itself.
|
||||||
|
unsigned int numImages;
|
||||||
|
const char **imageNames = objc_copyImageNames(&numImages);
|
||||||
|
for (unsigned int i = 0; i < numImages; i++) {
|
||||||
|
NSString *imageName = [NSString stringWithUTF8String:imageNames[i]];
|
||||||
|
if ([imageName rangeOfString:@"System/Library"].length != 0 // Apple .frameworks
|
||||||
|
|| [imageName rangeOfString:@"Developer/Library"].length != 0 // Xcode debug .frameworks
|
||||||
|
|| [imageName rangeOfString:@"usr/lib"].length != 0) { // Public .dylibs
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
numFrameworks++;
|
||||||
|
}
|
||||||
|
free(imageNames);
|
||||||
|
config->dynamic_framework_count = numFrameworks;
|
||||||
|
config->has_dynamic_framework_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates the proto with Info.plist values.
|
||||||
|
*
|
||||||
|
* @param config The proto to populate.
|
||||||
|
*/
|
||||||
|
void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
|
||||||
|
NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
|
||||||
|
|
||||||
|
NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @"";
|
||||||
|
NSString *sdkVersion = info[@"DTSDKBuild"] ?: @"";
|
||||||
|
NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion];
|
||||||
|
config->apple_framework_version = FIREncodeString(combinedVersions);
|
||||||
|
|
||||||
|
NSString *minVersion = info[@"MinimumOSVersion"];
|
||||||
|
if (minVersion) {
|
||||||
|
config->min_supported_ios_version = FIREncodeString(minVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apps can turn off swizzling in the Info.plist, check if they've explicitly set the value and
|
||||||
|
// report it. It's enabled by default.
|
||||||
|
NSNumber *appDelegateSwizzledNum = info[@"FirebaseAppDelegateProxyEnabled"];
|
||||||
|
BOOL appDelegateSwizzled = YES;
|
||||||
|
if ([appDelegateSwizzledNum isKindOfClass:[NSNumber class]]) {
|
||||||
|
appDelegateSwizzled = [appDelegateSwizzledNum boolValue];
|
||||||
|
}
|
||||||
|
config->swizzling_enabled = appDelegateSwizzled;
|
||||||
|
config->has_swizzling_enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - FIRCoreDiagnosticsInterop
|
||||||
|
|
||||||
|
+ (void)sendDiagnosticsData:(nonnull id<FIRCoreDiagnosticsData>)diagnosticsData {
|
||||||
|
FIRCoreDiagnostics *diagnostics = [FIRCoreDiagnostics sharedInstance];
|
||||||
|
[diagnostics sendDiagnosticsData:diagnosticsData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendDiagnosticsData:(nonnull id<FIRCoreDiagnosticsData>)diagnosticsData {
|
||||||
|
dispatch_async(self.diagnosticsQueue, ^{
|
||||||
|
NSDictionary<NSString *, id> *diagnosticObjects = diagnosticsData.diagnosticObjects;
|
||||||
|
NSNumber *isDataCollectionDefaultEnabled =
|
||||||
|
diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey];
|
||||||
|
if (isDataCollectionDefaultEnabled && ![isDataCollectionDefaultEnabled boolValue]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the proto.
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration icore_config =
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_init_default;
|
||||||
|
|
||||||
|
icore_config.using_gdt = 1;
|
||||||
|
icore_config.has_using_gdt = 1;
|
||||||
|
|
||||||
|
// Populate the proto with information.
|
||||||
|
FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects);
|
||||||
|
FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects);
|
||||||
|
FIRPopulateProtoWithInstalledServices(&icore_config);
|
||||||
|
FIRPopulateProtoWithNumberOfLinkedFrameworks(&icore_config);
|
||||||
|
FIRPopulateProtoWithInfoPlistValues(&icore_config);
|
||||||
|
[self setHeartbeatFlagIfNeededToConfig:&icore_config];
|
||||||
|
|
||||||
|
// This log object is capable of converting the proto to bytes.
|
||||||
|
FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config];
|
||||||
|
|
||||||
|
// Send the log as a telemetry event.
|
||||||
|
GDTEvent *event = [self.transport eventForTransport];
|
||||||
|
event.dataObject = (id<GDTEventDataObject>)log;
|
||||||
|
[self.transport sendTelemetryEvent:event];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Heartbeat
|
||||||
|
|
||||||
|
- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config {
|
||||||
|
// Check if need to send a heartbeat.
|
||||||
|
NSDate *currentDate = [NSDate date];
|
||||||
|
NSDate *lastCheckin = [self.heartbeatDateStorage date];
|
||||||
|
if (lastCheckin) {
|
||||||
|
// Ensure the previous checkin was on a different date in the past.
|
||||||
|
if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update heartbeat sent date.
|
||||||
|
NSError *error;
|
||||||
|
if (![self.heartbeatDateStorage setDate:currentDate error:&error]) {
|
||||||
|
GULLogError(kFIRCoreDiagnostics, NO, @"I-COR100004", @"Unable to persist internal state: %@",
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the flag.
|
||||||
|
config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE;
|
||||||
|
config->has_sdk_name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isDate:(NSDate *)date1 inSameDayOrBeforeThan:(NSDate *)date2 {
|
||||||
|
return [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2] ||
|
||||||
|
[date1 compare:date2] == NSOrderedAscending;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// Stores a date to a specified file.
|
||||||
|
@interface FIRCoreDiagnosticsDateFileStorage : NSObject
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default initializer.
|
||||||
|
* @param fileURL The URL of the file to store the date. The directory must exist, the file may not
|
||||||
|
* exist, it will be created if needed.
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithFileURL:(NSURL *)fileURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the date to the specified file.
|
||||||
|
* @return YES on success, NO otherwise.
|
||||||
|
*/
|
||||||
|
- (BOOL)setDate:(nullable NSDate *)date error:(NSError **)outError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the date to the specified file.
|
||||||
|
* @return Returns date if exists, otherwise `nil`.
|
||||||
|
*/
|
||||||
|
- (nullable NSDate *)date;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h"
|
||||||
|
|
||||||
|
@interface FIRCoreDiagnosticsDateFileStorage ()
|
||||||
|
@property(nonatomic, readonly) NSURL *fileURL;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FIRCoreDiagnosticsDateFileStorage
|
||||||
|
|
||||||
|
- (instancetype)initWithFileURL:(NSURL *)fileURL {
|
||||||
|
if (fileURL == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_fileURL = fileURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setDate:(nullable NSDate *)date error:(NSError **)outError {
|
||||||
|
NSString *stringToSave = @"";
|
||||||
|
|
||||||
|
if (date != nil) {
|
||||||
|
NSTimeInterval timestamp = [date timeIntervalSinceReferenceDate];
|
||||||
|
stringToSave = [NSString stringWithFormat:@"%f", timestamp];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [stringToSave writeToURL:self.fileURL
|
||||||
|
atomically:YES
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
|
error:outError];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSDate *)date {
|
||||||
|
NSString *timestampString = [NSString stringWithContentsOfURL:self.fileURL
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
|
error:nil];
|
||||||
|
if (timestampString.length == 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSTimeInterval timestamp = timestampString.doubleValue;
|
||||||
|
return [NSDate dateWithTimeIntervalSinceReferenceDate:timestamp];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Automatically generated nanopb constant definitions */
|
||||||
|
/* Generated by nanopb-0.3.9.2 */
|
||||||
|
|
||||||
|
#include "firebasecore.nanopb.h"
|
||||||
|
|
||||||
|
/* @@protoc_insertion_point(includes) */
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 30
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34] = {
|
||||||
|
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, logs_proto_mobilesdk_ios_ICoreConfiguration, configuration_type, configuration_type, 0),
|
||||||
|
PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, version_name, configuration_type, 0),
|
||||||
|
PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_number, version_name, 0),
|
||||||
|
PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_type, build_number, 0),
|
||||||
|
PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, plist_version, build_type, 0),
|
||||||
|
PB_FIELD( 6, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_enabled, plist_version, 0),
|
||||||
|
PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, sdk_service_enabled, 0),
|
||||||
|
PB_FIELD( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 0),
|
||||||
|
PB_FIELD( 10, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_id, device_model, 0),
|
||||||
|
PB_FIELD( 11, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, project_number, app_id, 0),
|
||||||
|
PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, project_number, 0),
|
||||||
|
PB_FIELD( 13, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, client_id, bundle_id, 0),
|
||||||
|
PB_FIELD( 14, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, install, client_id, 0),
|
||||||
|
PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, install, 0),
|
||||||
|
PB_FIELD( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 0),
|
||||||
|
PB_FIELD( 19, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_version, icore_version, 0),
|
||||||
|
PB_FIELD( 20, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_name, sdk_version, 0),
|
||||||
|
PB_FIELD( 21, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_count, sdk_name, 0),
|
||||||
|
PB_FIELD( 22, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, os_version, app_count, 0),
|
||||||
|
PB_FIELD( 23, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, itunes_id, os_version, 0),
|
||||||
|
PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, itunes_id, 0),
|
||||||
|
PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_version, 0),
|
||||||
|
PB_FIELD( 26, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployed_in_app_store, use_default_app, 0),
|
||||||
|
PB_FIELD( 27, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, dynamic_framework_count, deployed_in_app_store, 0),
|
||||||
|
PB_FIELD( 28, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, apple_framework_version, dynamic_framework_count, 0),
|
||||||
|
PB_FIELD( 29, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_zip_file, apple_framework_version, 0),
|
||||||
|
PB_FIELD( 30, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployment_type, using_zip_file, 0),
|
||||||
|
PB_FIELD( 31, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, platform_info, deployment_type, 0),
|
||||||
|
PB_FIELD( 32, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_extensions, platform_info, 0),
|
||||||
|
PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, app_extensions, 0),
|
||||||
|
PB_FIELD( 34, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_error_count, swizzling_enabled, 0),
|
||||||
|
PB_FIELD( 35, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_warning_count, log_error_count, 0),
|
||||||
|
PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, log_warning_count, 0),
|
||||||
|
PB_LAST_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* @@protoc_insertion_point(eof) */
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Automatically generated nanopb header */
|
||||||
|
/* Generated by nanopb-0.3.9.2 */
|
||||||
|
|
||||||
|
#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||||
|
#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||||
|
#include <nanopb/pb.h>
|
||||||
|
|
||||||
|
/* @@protoc_insertion_point(includes) */
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 30
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Enum definitions */
|
||||||
|
typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType {
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE = 0,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE = 1,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK = 2
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType;
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK+1))
|
||||||
|
|
||||||
|
typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType {
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE = 0,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_INTERNAL = 1,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_EAP = 2,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD = 3
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType;
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType)(logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD+1))
|
||||||
|
|
||||||
|
typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType {
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE = 0,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE = 1,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB = 2,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INVITE = 3,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN = 5,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_GCM = 6,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAPS = 7,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SCION = 8,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS = 9,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INDEXING = 10,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CONFIG = 11,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DURABLE_DEEP_LINKS = 12,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CRASH = 13,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH = 14,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE = 15,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE = 16,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING = 17,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT = 18,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG = 19,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS = 20,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_INVITES = 21,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI = 22,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE = 23,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE = 24,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE = 26,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE = 27,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT = 28,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL = 29,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER = 30,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING = 31,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS = 32,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_NATURAL_LANGUAGE = 33,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML = 34,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION = 35
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType;
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION+1))
|
||||||
|
|
||||||
|
typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName {
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME = 0,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_GOOGLE = 1,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE = 2
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration_PodName;
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_PodName)(logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE+1))
|
||||||
|
|
||||||
|
typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType {
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN = 0,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS = 1,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE = 2,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE = 3,
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM = 4
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType;
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM
|
||||||
|
#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType)(logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM+1))
|
||||||
|
|
||||||
|
/* Struct definitions */
|
||||||
|
typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration {
|
||||||
|
bool has_configuration_type;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType configuration_type;
|
||||||
|
pb_bytes_array_t *version_name;
|
||||||
|
bool has_build_number;
|
||||||
|
int64_t build_number;
|
||||||
|
bool has_build_type;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType build_type;
|
||||||
|
pb_bytes_array_t *plist_version;
|
||||||
|
pb_size_t sdk_service_enabled_count;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_enabled;
|
||||||
|
pb_size_t sdk_service_installed_count;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed;
|
||||||
|
pb_bytes_array_t *device_model;
|
||||||
|
pb_bytes_array_t *app_id;
|
||||||
|
bool has_project_number;
|
||||||
|
int64_t project_number;
|
||||||
|
pb_bytes_array_t *bundle_id;
|
||||||
|
pb_bytes_array_t *client_id;
|
||||||
|
pb_bytes_array_t *install;
|
||||||
|
bool has_pod_name;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name;
|
||||||
|
pb_bytes_array_t *icore_version;
|
||||||
|
pb_bytes_array_t *sdk_version;
|
||||||
|
bool has_sdk_name;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType sdk_name;
|
||||||
|
bool has_app_count;
|
||||||
|
int32_t app_count;
|
||||||
|
pb_bytes_array_t *os_version;
|
||||||
|
pb_bytes_array_t *itunes_id;
|
||||||
|
pb_bytes_array_t *min_supported_ios_version;
|
||||||
|
bool has_use_default_app;
|
||||||
|
bool use_default_app;
|
||||||
|
bool has_deployed_in_app_store;
|
||||||
|
bool deployed_in_app_store;
|
||||||
|
bool has_dynamic_framework_count;
|
||||||
|
int32_t dynamic_framework_count;
|
||||||
|
pb_bytes_array_t *apple_framework_version;
|
||||||
|
bool has_using_zip_file;
|
||||||
|
bool using_zip_file;
|
||||||
|
bool has_deployment_type;
|
||||||
|
logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type;
|
||||||
|
pb_bytes_array_t *platform_info;
|
||||||
|
bool has_app_extensions;
|
||||||
|
int64_t app_extensions;
|
||||||
|
bool has_swizzling_enabled;
|
||||||
|
bool swizzling_enabled;
|
||||||
|
bool has_log_error_count;
|
||||||
|
int32_t log_error_count;
|
||||||
|
bool has_log_warning_count;
|
||||||
|
int32_t log_warning_count;
|
||||||
|
bool has_using_gdt;
|
||||||
|
bool using_gdt;
|
||||||
|
/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */
|
||||||
|
} logs_proto_mobilesdk_ios_ICoreConfiguration;
|
||||||
|
|
||||||
|
/* Default values for struct fields */
|
||||||
|
|
||||||
|
/* Initializer values for message structs */
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
|
|
||||||
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_configuration_type_tag 1
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_version_name_tag 2
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_icore_version_tag 18
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_number_tag 3
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_type_tag 4
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_plist_version_tag 5
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_enabled_tag 6
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_installed_tag 7
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_device_model_tag 9
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_id_tag 10
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_project_number_tag 11
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_bundle_id_tag 12
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_client_id_tag 13
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_itunes_id_tag 23
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_min_supported_ios_version_tag 24
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_install_tag 14
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_use_default_app_tag 25
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_dynamic_framework_count_tag 27
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_apple_framework_version_tag 28
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_zip_file_tag 29
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_platform_info_tag 31
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_extensions_tag 32
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_swizzling_enabled_tag 33
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_error_count_tag 34
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_warning_count_tag 35
|
||||||
|
#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36
|
||||||
|
|
||||||
|
/* Struct field encoding specification for nanopb */
|
||||||
|
extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34];
|
||||||
|
|
||||||
|
/* Maximum encoded size of messages (where known) */
|
||||||
|
/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */
|
||||||
|
|
||||||
|
/* Message IDs (where set with "msgid" option) */
|
||||||
|
#ifdef PB_MSGID
|
||||||
|
|
||||||
|
#define FIREBASECORE_MESSAGES \
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* @@protoc_insertion_point(eof) */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,223 @@
|
||||||
|
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||||
|
|
||||||
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
|
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
||||||
|
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
|
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||||
|
|
||||||
|
The repository also includes GoogleUtilities source. The
|
||||||
|
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||||
|
a set of utilities used by Firebase and other Google products.
|
||||||
|
|
||||||
|
Firebase is an app development platform with tools to help you build, grow and
|
||||||
|
monetize your app. More information about Firebase can be found at
|
||||||
|
[https://firebase.google.com](https://firebase.google.com).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
See the three subsections for details about three different installation methods.
|
||||||
|
1. [Standard pod install](README.md#standard-pod-install)
|
||||||
|
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||||
|
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||||
|
|
||||||
|
### Standard pod install
|
||||||
|
|
||||||
|
Go to
|
||||||
|
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||||
|
|
||||||
|
### Installing from GitHub
|
||||||
|
|
||||||
|
For releases starting with 5.0.0, the source for each release is also deployed
|
||||||
|
to CocoaPods master and available via standard
|
||||||
|
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||||
|
|
||||||
|
These instructions can be used to access the Firebase repo at other branches,
|
||||||
|
tags, or commits.
|
||||||
|
|
||||||
|
#### Background
|
||||||
|
|
||||||
|
See
|
||||||
|
[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
|
||||||
|
for instructions and options about overriding pod source locations.
|
||||||
|
|
||||||
|
#### Accessing Firebase Source Snapshots
|
||||||
|
|
||||||
|
All of the official releases are tagged in this repo and available via CocoaPods. To access a local
|
||||||
|
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||||
|
|
||||||
|
To access FirebaseFirestore via a branch:
|
||||||
|
```
|
||||||
|
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
|
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
|
```
|
||||||
|
|
||||||
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
|
```
|
||||||
|
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||||
|
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Carthage (iOS only)
|
||||||
|
|
||||||
|
Instructions for the experimental Carthage distribution are at
|
||||||
|
[Carthage](Carthage.md).
|
||||||
|
|
||||||
|
### Rome
|
||||||
|
|
||||||
|
Instructions for installing binary frameworks via
|
||||||
|
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
|
the following software:
|
||||||
|
|
||||||
|
* Xcode 10.1 (or later)
|
||||||
|
* CocoaPods 1.7.2 (or later)
|
||||||
|
|
||||||
|
For the pod that you want to develop:
|
||||||
|
|
||||||
|
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||||
|
|
||||||
|
Firestore and Functions have self contained Xcode projects. See
|
||||||
|
[Firestore/README.md](Firestore/README.md) and
|
||||||
|
[Functions/README.md](Functions/README.md).
|
||||||
|
|
||||||
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
|
See [AddNewPod.md](AddNewPod.md).
|
||||||
|
|
||||||
|
### Code Formatting
|
||||||
|
|
||||||
|
To ensure that the code is formatted consistently, run the script
|
||||||
|
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
||||||
|
before creating a PR.
|
||||||
|
|
||||||
|
Travis will verify that any code changes are done in a style compliant way. Install
|
||||||
|
`clang-format` and `swiftformat`.
|
||||||
|
These commands will get the right versions:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
||||||
|
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: if you already have a newer version of these installed you may need to
|
||||||
|
`brew switch` to this version.
|
||||||
|
|
||||||
|
### Running Unit Tests
|
||||||
|
|
||||||
|
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||||
|
|
||||||
|
#### Viewing Code Coverage
|
||||||
|
|
||||||
|
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
||||||
|
|
||||||
|
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
||||||
|
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
||||||
|
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
||||||
|
|
||||||
|
### Running Sample Apps
|
||||||
|
In order to run the sample apps and integration tests, you'll need valid
|
||||||
|
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||||
|
files without real values, but can be replaced with real plist files. To get your own
|
||||||
|
`GoogleService-Info.plist` files:
|
||||||
|
|
||||||
|
1. Go to the [Firebase Console](https://console.firebase.google.com/)
|
||||||
|
2. Create a new Firebase project, if you don't already have one
|
||||||
|
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||||
|
identifier (e.g. `com.google.Database-Example`)
|
||||||
|
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||||
|
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||||
|
|
||||||
|
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||||
|
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
||||||
|
identifier that you can control in your own Apple Developer account.
|
||||||
|
|
||||||
|
## Specific Component Instructions
|
||||||
|
See the sections below for any special instructions for those components.
|
||||||
|
|
||||||
|
### Firebase Auth
|
||||||
|
|
||||||
|
If you're doing specific Firebase Auth development, see
|
||||||
|
[the Auth Sample README](Example/Auth/README.md) for instructions about
|
||||||
|
building and running the FirebaseAuth pod along with various samples and tests.
|
||||||
|
|
||||||
|
### Firebase Database
|
||||||
|
|
||||||
|
To run the Database Integration tests, make your database authentication rules
|
||||||
|
[public](https://firebase.google.com/docs/database/security/quickstart).
|
||||||
|
|
||||||
|
### Firebase Storage
|
||||||
|
|
||||||
|
To run the Storage Integration tests, follow the instructions in
|
||||||
|
[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m).
|
||||||
|
|
||||||
|
#### Push Notifications
|
||||||
|
|
||||||
|
Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
|
||||||
|
In order to actually test receiving push notifications, you will need to:
|
||||||
|
|
||||||
|
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||||
|
account, and enable that App ID for push notifications.
|
||||||
|
2. You'll also need to
|
||||||
|
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||||
|
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||||
|
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||||
|
|
||||||
|
#### iOS Simulator
|
||||||
|
|
||||||
|
The iOS Simulator cannot register for remote notifications, and will not receive push notifications.
|
||||||
|
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||||
|
physical device.
|
||||||
|
|
||||||
|
## Community Supported Efforts
|
||||||
|
|
||||||
|
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||||
|
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||||
|
participate in the Firebase community.
|
||||||
|
|
||||||
|
### macOS and tvOS
|
||||||
|
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
||||||
|
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||||
|
macOS and tvOS.
|
||||||
|
|
||||||
|
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||||
|
|
||||||
|
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
||||||
|
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
||||||
|
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
||||||
|
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||||
|
|
||||||
|
Note that the Firebase pod is not available for macOS and tvOS.
|
||||||
|
|
||||||
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
|
```
|
||||||
|
pod 'FirebaseAuth'
|
||||||
|
pod 'FirebaseCore'
|
||||||
|
pod 'FirebaseDatabase'
|
||||||
|
pod 'FirebaseFirestore'
|
||||||
|
pod 'FirebaseFunctions'
|
||||||
|
pod 'FirebaseMessaging'
|
||||||
|
pod 'FirebaseStorage'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
plans and directions.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
|
||||||
|
iOS SDK.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The contents of this repository is licensed under the
|
||||||
|
[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
|
Your use of Firebase is governed by the
|
||||||
|
[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
|
63
ios/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h
generated
Normal file
63
ios/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h
generated
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||||
|
static NSString *const kFIRCDIsDataCollectionDefaultEnabledKey =
|
||||||
|
@"FIRCDIsDataCollectionDefaultEnabledKey";
|
||||||
|
|
||||||
|
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||||
|
static NSString *const kFIRCDConfigurationTypeKey = @"FIRCDConfigurationTypeKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDSdkNameKey = @"FIRCDSdkNameKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDSdkVersionKey = @"FIRCDSdkVersionKey";
|
||||||
|
|
||||||
|
/** If present, is an int32_t wrapped in an NSNumber. */
|
||||||
|
static NSString *const kFIRCDllAppsCountKey = @"FIRCDllAppsCountKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDGoogleAppIDKey = @"FIRCDGoogleAppIDKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDBundleIDKey = @"FIRCDBundleID";
|
||||||
|
|
||||||
|
/** If present, is a BOOL wrapped in an NSNumber. */
|
||||||
|
static NSString *const kFIRCDUsingOptionsFromDefaultPlistKey =
|
||||||
|
@"FIRCDUsingOptionsFromDefaultPlistKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDLibraryVersionIDKey = @"FIRCDLibraryVersionIDKey";
|
||||||
|
|
||||||
|
/** If present, is an NSString. */
|
||||||
|
static NSString *const kFIRCDFirebaseUserAgentKey = @"FIRCDFirebaseUserAgentKey";
|
||||||
|
|
||||||
|
/** Defines the interface of a data object needed to log diagnostics data. */
|
||||||
|
@protocol FIRCoreDiagnosticsData <NSObject>
|
||||||
|
|
||||||
|
@required
|
||||||
|
|
||||||
|
/** A dictionary containing data (non-exhaustive) to be logged in diagnostics. */
|
||||||
|
@property(nonatomic) NSDictionary<NSString *, id> *diagnosticObjects;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
34
ios/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h
generated
Normal file
34
ios/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h
generated
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "FIRCoreDiagnosticsData.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** Allows the interoperation of FirebaseCore and FirebaseCoreDiagnostics. */
|
||||||
|
@protocol FIRCoreDiagnosticsInterop <NSObject>
|
||||||
|
|
||||||
|
/** Sends the given diagnostics data.
|
||||||
|
*
|
||||||
|
* @param diagnosticsData The diagnostics data object to send.
|
||||||
|
*/
|
||||||
|
+ (void)sendDiagnosticsData:(id<FIRCoreDiagnosticsData>)diagnosticsData;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,223 @@
|
||||||
|
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||||
|
|
||||||
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
|
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
||||||
|
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
|
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||||
|
|
||||||
|
The repository also includes GoogleUtilities source. The
|
||||||
|
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
||||||
|
a set of utilities used by Firebase and other Google products.
|
||||||
|
|
||||||
|
Firebase is an app development platform with tools to help you build, grow and
|
||||||
|
monetize your app. More information about Firebase can be found at
|
||||||
|
[https://firebase.google.com](https://firebase.google.com).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
See the three subsections for details about three different installation methods.
|
||||||
|
1. [Standard pod install](README.md#standard-pod-install)
|
||||||
|
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||||
|
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||||
|
|
||||||
|
### Standard pod install
|
||||||
|
|
||||||
|
Go to
|
||||||
|
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||||
|
|
||||||
|
### Installing from GitHub
|
||||||
|
|
||||||
|
For releases starting with 5.0.0, the source for each release is also deployed
|
||||||
|
to CocoaPods master and available via standard
|
||||||
|
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||||
|
|
||||||
|
These instructions can be used to access the Firebase repo at other branches,
|
||||||
|
tags, or commits.
|
||||||
|
|
||||||
|
#### Background
|
||||||
|
|
||||||
|
See
|
||||||
|
[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
|
||||||
|
for instructions and options about overriding pod source locations.
|
||||||
|
|
||||||
|
#### Accessing Firebase Source Snapshots
|
||||||
|
|
||||||
|
All of the official releases are tagged in this repo and available via CocoaPods. To access a local
|
||||||
|
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||||
|
|
||||||
|
To access FirebaseFirestore via a branch:
|
||||||
|
```
|
||||||
|
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
|
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
|
```
|
||||||
|
|
||||||
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
|
```
|
||||||
|
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||||
|
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Carthage (iOS only)
|
||||||
|
|
||||||
|
Instructions for the experimental Carthage distribution are at
|
||||||
|
[Carthage](Carthage.md).
|
||||||
|
|
||||||
|
### Rome
|
||||||
|
|
||||||
|
Instructions for installing binary frameworks via
|
||||||
|
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
|
the following software:
|
||||||
|
|
||||||
|
* Xcode 10.1 (or later)
|
||||||
|
* CocoaPods 1.7.2 (or later)
|
||||||
|
|
||||||
|
For the pod that you want to develop:
|
||||||
|
|
||||||
|
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||||
|
|
||||||
|
Firestore and Functions have self contained Xcode projects. See
|
||||||
|
[Firestore/README.md](Firestore/README.md) and
|
||||||
|
[Functions/README.md](Functions/README.md).
|
||||||
|
|
||||||
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
|
See [AddNewPod.md](AddNewPod.md).
|
||||||
|
|
||||||
|
### Code Formatting
|
||||||
|
|
||||||
|
To ensure that the code is formatted consistently, run the script
|
||||||
|
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
||||||
|
before creating a PR.
|
||||||
|
|
||||||
|
Travis will verify that any code changes are done in a style compliant way. Install
|
||||||
|
`clang-format` and `swiftformat`.
|
||||||
|
These commands will get the right versions:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
|
||||||
|
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: if you already have a newer version of these installed you may need to
|
||||||
|
`brew switch` to this version.
|
||||||
|
|
||||||
|
### Running Unit Tests
|
||||||
|
|
||||||
|
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||||
|
|
||||||
|
#### Viewing Code Coverage
|
||||||
|
|
||||||
|
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
||||||
|
|
||||||
|
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
||||||
|
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
||||||
|
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
||||||
|
|
||||||
|
### Running Sample Apps
|
||||||
|
In order to run the sample apps and integration tests, you'll need valid
|
||||||
|
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||||
|
files without real values, but can be replaced with real plist files. To get your own
|
||||||
|
`GoogleService-Info.plist` files:
|
||||||
|
|
||||||
|
1. Go to the [Firebase Console](https://console.firebase.google.com/)
|
||||||
|
2. Create a new Firebase project, if you don't already have one
|
||||||
|
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||||
|
identifier (e.g. `com.google.Database-Example`)
|
||||||
|
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||||
|
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||||
|
|
||||||
|
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||||
|
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
||||||
|
identifier that you can control in your own Apple Developer account.
|
||||||
|
|
||||||
|
## Specific Component Instructions
|
||||||
|
See the sections below for any special instructions for those components.
|
||||||
|
|
||||||
|
### Firebase Auth
|
||||||
|
|
||||||
|
If you're doing specific Firebase Auth development, see
|
||||||
|
[the Auth Sample README](Example/Auth/README.md) for instructions about
|
||||||
|
building and running the FirebaseAuth pod along with various samples and tests.
|
||||||
|
|
||||||
|
### Firebase Database
|
||||||
|
|
||||||
|
To run the Database Integration tests, make your database authentication rules
|
||||||
|
[public](https://firebase.google.com/docs/database/security/quickstart).
|
||||||
|
|
||||||
|
### Firebase Storage
|
||||||
|
|
||||||
|
To run the Storage Integration tests, follow the instructions in
|
||||||
|
[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m).
|
||||||
|
|
||||||
|
#### Push Notifications
|
||||||
|
|
||||||
|
Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
|
||||||
|
In order to actually test receiving push notifications, you will need to:
|
||||||
|
|
||||||
|
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||||
|
account, and enable that App ID for push notifications.
|
||||||
|
2. You'll also need to
|
||||||
|
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||||
|
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||||
|
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||||
|
|
||||||
|
#### iOS Simulator
|
||||||
|
|
||||||
|
The iOS Simulator cannot register for remote notifications, and will not receive push notifications.
|
||||||
|
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||||
|
physical device.
|
||||||
|
|
||||||
|
## Community Supported Efforts
|
||||||
|
|
||||||
|
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||||
|
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||||
|
participate in the Firebase community.
|
||||||
|
|
||||||
|
### macOS and tvOS
|
||||||
|
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
||||||
|
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||||
|
macOS and tvOS.
|
||||||
|
|
||||||
|
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||||
|
|
||||||
|
Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
|
||||||
|
actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
|
||||||
|
may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
|
||||||
|
this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||||
|
|
||||||
|
Note that the Firebase pod is not available for macOS and tvOS.
|
||||||
|
|
||||||
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
|
```
|
||||||
|
pod 'FirebaseAuth'
|
||||||
|
pod 'FirebaseCore'
|
||||||
|
pod 'FirebaseDatabase'
|
||||||
|
pod 'FirebaseFirestore'
|
||||||
|
pod 'FirebaseFunctions'
|
||||||
|
pod 'FirebaseMessaging'
|
||||||
|
pod 'FirebaseStorage'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
plans and directions.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
|
||||||
|
iOS SDK.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The contents of this repository is licensed under the
|
||||||
|
[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
|
Your use of Firebase is governed by the
|
||||||
|
[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
|
|
@ -44,6 +44,8 @@ typedef NS_ENUM(NSInteger, FIRInstanceIDMessageCode) {
|
||||||
kFIRInstanceIDMessageCodeInstanceID014 = 3014,
|
kFIRInstanceIDMessageCodeInstanceID014 = 3014,
|
||||||
kFIRInstanceIDMessageCodeInstanceID015 = 3015,
|
kFIRInstanceIDMessageCodeInstanceID015 = 3015,
|
||||||
kFIRInstanceIDMessageCodeRefetchingTokenForAPNS = 3016,
|
kFIRInstanceIDMessageCodeRefetchingTokenForAPNS = 3016,
|
||||||
|
kFIRInstanceIDMessageCodeInstanceID017 = 3017,
|
||||||
|
kFIRInstanceIDMessageCodeInstanceID018 = 3018,
|
||||||
// FIRInstanceIDAuthService.m
|
// FIRInstanceIDAuthService.m
|
||||||
kFIRInstanceIDMessageCodeAuthService000 = 5000,
|
kFIRInstanceIDMessageCodeAuthService000 = 5000,
|
||||||
kFIRInstanceIDMessageCodeAuthService001 = 5001,
|
kFIRInstanceIDMessageCodeAuthService001 = 5001,
|
||||||
|
|
|
@ -1012,6 +1012,16 @@ static FIRInstanceID *gInstanceID;
|
||||||
FIRInstanceID_WEAKIFY(self);
|
FIRInstanceID_WEAKIFY(self);
|
||||||
[self asyncLoadKeyPairWithHandler:^(FIRInstanceIDKeyPair *keyPair, NSError *error) {
|
[self asyncLoadKeyPairWithHandler:^(FIRInstanceIDKeyPair *keyPair, NSError *error) {
|
||||||
FIRInstanceID_STRONGIFY(self);
|
FIRInstanceID_STRONGIFY(self);
|
||||||
|
if (self == nil) {
|
||||||
|
FIRInstanceIDLoggerError(kFIRInstanceIDMessageCodeInstanceID017,
|
||||||
|
@"Instance ID shut down during token reset. Aborting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.apnsTokenData == nil) {
|
||||||
|
FIRInstanceIDLoggerError(kFIRInstanceIDMessageCodeInstanceID018,
|
||||||
|
@"apnsTokenData was set to nil during token reset. Aborting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSMutableDictionary *tokenOptions = [@{
|
NSMutableDictionary *tokenOptions = [@{
|
||||||
kFIRInstanceIDTokenOptionsAPNSKey : self.apnsTokenData,
|
kFIRInstanceIDTokenOptionsAPNSKey : self.apnsTokenData,
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "FIRInstanceIDCheckinPreferences.h"
|
#import <FirebaseInstanceID/FIRInstanceIDCheckinPreferences.h>
|
||||||
|
|
||||||
@interface FIRInstanceIDCheckinPreferences (Internal)
|
@interface FIRInstanceIDCheckinPreferences (Internal)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "FIRInstanceIDCheckinPreferences.h"
|
#import <FirebaseInstanceID/FIRInstanceIDCheckinPreferences.h>
|
||||||
|
|
||||||
/** Checkin refresh interval. **/
|
/** Checkin refresh interval. **/
|
||||||
FOUNDATION_EXPORT const NSTimeInterval kFIRInstanceIDDefaultCheckinInterval;
|
FOUNDATION_EXPORT const NSTimeInterval kFIRInstanceIDDefaultCheckinInterval;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <FirebaseInstanceID/FIRInstanceID+Private.h>
|
||||||
#import "FIRInstanceIDUtilities.h"
|
#import "FIRInstanceIDUtilities.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
@ -31,20 +32,6 @@ FOUNDATION_EXPORT NSString *const kFIRInstanceIDDeviceDataVersionKey;
|
||||||
|
|
||||||
@class FIRInstanceIDCheckinPreferences;
|
@class FIRInstanceIDCheckinPreferences;
|
||||||
|
|
||||||
/**
|
|
||||||
* @related FIRInstanceIDCheckinService
|
|
||||||
*
|
|
||||||
* The completion handler invoked once the fetch from Checkin server finishes.
|
|
||||||
* For successful fetches we returned checkin information by the checkin service
|
|
||||||
* and `nil` error, else we return the appropriate error object as reported by the
|
|
||||||
* Checkin Service.
|
|
||||||
*
|
|
||||||
* @param checkinPreferences The checkin preferences as fetched from the server.
|
|
||||||
* @param error The error object which fetching GServices data.
|
|
||||||
*/
|
|
||||||
typedef void (^FIRInstanceIDDeviceCheckinCompletion)(
|
|
||||||
FIRInstanceIDCheckinPreferences *_Nullable checkinPreferences, NSError *_Nullable error);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the device with Checkin Service and get back the `authID`, `secret
|
* Register the device with Checkin Service and get back the `authID`, `secret
|
||||||
* token` etc. for the client. Checkin results are cached in the
|
* token` etc. for the client. Checkin results are cached in the
|
||||||
|
|
|
@ -14,14 +14,26 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "FIRInstanceID.h"
|
#import <FirebaseInstanceID/FIRInstanceID.h>
|
||||||
|
#import <FirebaseInstanceID/FIRInstanceIDCheckinPreferences.h>
|
||||||
#import "FIRInstanceIDCheckinService.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal API used by Firebase SDK teams by calling in reflection or internal teams.
|
* @related FIRInstanceIDCheckinService
|
||||||
|
*
|
||||||
|
* The completion handler invoked once the fetch from Checkin server finishes.
|
||||||
|
* For successful fetches we returned checkin information by the checkin service
|
||||||
|
* and `nil` error, else we return the appropriate error object as reported by the
|
||||||
|
* Checkin Service.
|
||||||
|
*
|
||||||
|
* @param checkinPreferences The checkin preferences as fetched from the server.
|
||||||
|
* @param error The error object which fetching GServices data.
|
||||||
|
*/
|
||||||
|
typedef void (^FIRInstanceIDDeviceCheckinCompletion)(
|
||||||
|
FIRInstanceIDCheckinPreferences *_Nullable checkinPreferences, NSError *_Nullable error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private API used by Firebase SDK teams by calling in reflection or internal teams.
|
||||||
*/
|
*/
|
||||||
// TODO(chliangGoogle) Rename this to Internal.
|
|
||||||
@interface FIRInstanceID (Private)
|
@interface FIRInstanceID (Private)
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,8 +1,8 @@
|
||||||
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
|
||||||
|
|
||||||
This repository contains a subset of the Firebase iOS SDK source. It currently
|
This repository contains a subset of the Firebase iOS SDK source. It currently
|
||||||
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
|
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
|
||||||
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
|
||||||
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
The repository also includes GoogleUtilities source. The
|
||||||
|
@ -80,9 +80,8 @@ For the pod that you want to develop:
|
||||||
|
|
||||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
|
||||||
|
|
||||||
Firestore and Functions have self contained Xcode projects. See
|
Firestore has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md) and
|
[Firestore/README.md](Firestore/README.md).
|
||||||
[Functions/README.md](Functions/README.md).
|
|
||||||
|
|
||||||
### Adding a New Firebase Pod
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
|
@ -179,7 +178,8 @@ very grateful! We'd like to empower as many developers as we can to be able to
|
||||||
participate in the Firebase community.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### macOS and tvOS
|
### macOS and tvOS
|
||||||
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
|
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
|
||||||
|
FirebaseDatabase, FirebaseMessaging,
|
||||||
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
|
||||||
macOS and tvOS.
|
macOS and tvOS.
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ Note that the Firebase pod is not available for macOS and tvOS.
|
||||||
To install, add a subset of the following to the Podfile:
|
To install, add a subset of the following to the Podfile:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
pod 'FirebaseABTesting'
|
||||||
pod 'FirebaseAuth'
|
pod 'FirebaseAuth'
|
||||||
pod 'FirebaseCore'
|
pod 'FirebaseCore'
|
||||||
pod 'FirebaseDatabase'
|
pod 'FirebaseDatabase'
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Public/GDTAssert.h"
|
||||||
|
|
||||||
|
GDTAssertionBlock GDTAssertionBlockToRunInstead(void) {
|
||||||
|
// This class is only compiled in by unit tests, and this should fail quickly in optimized builds.
|
||||||
|
Class GDTAssertClass = NSClassFromString(@"GDTAssertHelper");
|
||||||
|
if (__builtin_expect(!!GDTAssertClass, 0)) {
|
||||||
|
SEL assertionBlockSEL = NSSelectorFromString(@"assertionBlock");
|
||||||
|
if (assertionBlockSEL) {
|
||||||
|
IMP assertionBlockIMP = [GDTAssertClass methodForSelector:assertionBlockSEL];
|
||||||
|
if (assertionBlockIMP) {
|
||||||
|
GDTAssertionBlock assertionBlock =
|
||||||
|
((GDTAssertionBlock(*)(id, SEL))assertionBlockIMP)(GDTAssertClass, assertionBlockSEL);
|
||||||
|
if (assertionBlock) {
|
||||||
|
return assertionBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Public/GDTClock.h"
|
||||||
|
|
||||||
|
#import <sys/sysctl.h>
|
||||||
|
|
||||||
|
// Using a monotonic clock is necessary because CFAbsoluteTimeGetCurrent(), NSDate, and related all
|
||||||
|
// are subject to drift. That it to say, multiple consecutive calls do not always result in a
|
||||||
|
// time that is in the future. Clocks may be adjusted by the user, NTP, or any number of external
|
||||||
|
// factors. This class attempts to determine the wall-clock time at the time of the event by
|
||||||
|
// capturing the kernel start and time since boot to determine a wallclock time in UTC.
|
||||||
|
//
|
||||||
|
// Timezone offsets at the time of a snapshot are also captured in order to provide local-time
|
||||||
|
// details. Other classes in this library depend on comparing times at some time in the future to
|
||||||
|
// a time captured in the past, and this class needs to provide a mechanism to do that.
|
||||||
|
//
|
||||||
|
// TL;DR: This class attempts to accomplish two things: 1. Provide accurate event times. 2. Provide
|
||||||
|
// a monotonic clock mechanism to accurately check if some clock snapshot was before or after
|
||||||
|
// by using a shared reference point (kernel boot time).
|
||||||
|
//
|
||||||
|
// Note: Much of the mach time stuff doesn't work properly in the simulator. So this class can be
|
||||||
|
// difficult to unit test.
|
||||||
|
|
||||||
|
/** Returns the kernel boottime property from sysctl.
|
||||||
|
*
|
||||||
|
* Inspired by https://stackoverflow.com/a/40497811
|
||||||
|
*
|
||||||
|
* @return The KERN_BOOTTIME property from sysctl, in nanoseconds.
|
||||||
|
*/
|
||||||
|
static int64_t KernelBootTimeInNanoseconds() {
|
||||||
|
// Caching the result is not possible because clock drift would not be accounted for.
|
||||||
|
struct timeval boottime;
|
||||||
|
int mib[2] = {CTL_KERN, KERN_BOOTTIME};
|
||||||
|
size_t size = sizeof(boottime);
|
||||||
|
int rc = sysctl(mib, 2, &boottime, &size, NULL, 0);
|
||||||
|
if (rc != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int64_t)boottime.tv_sec * NSEC_PER_MSEC + (int64_t)boottime.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns value of gettimeofday, in nanoseconds.
|
||||||
|
*
|
||||||
|
* Inspired by https://stackoverflow.com/a/40497811
|
||||||
|
*
|
||||||
|
* @return The value of gettimeofday, in nanoseconds.
|
||||||
|
*/
|
||||||
|
static int64_t UptimeInNanoseconds() {
|
||||||
|
int64_t before_now;
|
||||||
|
int64_t after_now;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
before_now = KernelBootTimeInNanoseconds();
|
||||||
|
// Addresses a race condition in which the system time has updated, but the boottime has not.
|
||||||
|
do {
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
after_now = KernelBootTimeInNanoseconds();
|
||||||
|
} while (after_now != before_now);
|
||||||
|
return (int64_t)now.tv_sec * NSEC_PER_MSEC + (int64_t)now.tv_usec - before_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Consider adding a 'trustedTime' property that can be populated by the response from a BE.
|
||||||
|
@implementation GDTClock
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_kernelBootTime = KernelBootTimeInNanoseconds();
|
||||||
|
_uptime = UptimeInNanoseconds();
|
||||||
|
_timeMillis =
|
||||||
|
(int64_t)((CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) * NSEC_PER_USEC);
|
||||||
|
CFTimeZoneRef timeZoneRef = CFTimeZoneCopySystem();
|
||||||
|
_timezoneOffsetSeconds = CFTimeZoneGetSecondsFromGMT(timeZoneRef, 0);
|
||||||
|
CFRelease(timeZoneRef);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (GDTClock *)snapshot {
|
||||||
|
return [[GDTClock alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture {
|
||||||
|
GDTClock *snapshot = [self snapshot];
|
||||||
|
snapshot->_timeMillis += millisInTheFuture;
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isAfter:(GDTClock *)otherClock {
|
||||||
|
// These clocks are trivially comparable when they share a kernel boot time.
|
||||||
|
if (_kernelBootTime == otherClock->_kernelBootTime) {
|
||||||
|
int64_t timeDiff = (_timeMillis + _timezoneOffsetSeconds) -
|
||||||
|
(otherClock->_timeMillis + otherClock->_timezoneOffsetSeconds);
|
||||||
|
return timeDiff > 0;
|
||||||
|
} else {
|
||||||
|
int64_t kernelBootTimeDiff = otherClock->_kernelBootTime - _kernelBootTime;
|
||||||
|
// This isn't a great solution, but essentially, if the other clock's boot time is 'later', NO
|
||||||
|
// is returned. This can be altered by changing the system time and rebooting.
|
||||||
|
return kernelBootTimeDiff < 0 ? YES : NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
return [@(_kernelBootTime) hash] ^ [@(_uptime) hash] ^ [@(_timeMillis) hash] ^
|
||||||
|
[@(_timezoneOffsetSeconds) hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
return [self hash] == [object hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
/** NSKeyedCoder key for timeMillis property. */
|
||||||
|
static NSString *const kGDTClockTimeMillisKey = @"GDTClockTimeMillis";
|
||||||
|
|
||||||
|
/** NSKeyedCoder key for timezoneOffsetMillis property. */
|
||||||
|
static NSString *const kGDTClockTimezoneOffsetSeconds = @"GDTClockTimezoneOffsetSeconds";
|
||||||
|
|
||||||
|
/** NSKeyedCoder key for _kernelBootTime ivar. */
|
||||||
|
static NSString *const kGDTClockKernelBootTime = @"GDTClockKernelBootTime";
|
||||||
|
|
||||||
|
/** NSKeyedCoder key for _uptime ivar. */
|
||||||
|
static NSString *const kGDTClockUptime = @"GDTClockUptime";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
// TODO: If the kernelBootTime is more recent, we need to change the kernel boot time and
|
||||||
|
// uptimeMillis ivars
|
||||||
|
_timeMillis = [aDecoder decodeInt64ForKey:kGDTClockTimeMillisKey];
|
||||||
|
_timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTClockTimezoneOffsetSeconds];
|
||||||
|
_kernelBootTime = [aDecoder decodeInt64ForKey:kGDTClockKernelBootTime];
|
||||||
|
_uptime = [aDecoder decodeInt64ForKey:kGDTClockUptime];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||||
|
[aCoder encodeInt64:_timeMillis forKey:kGDTClockTimeMillisKey];
|
||||||
|
[aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTClockTimezoneOffsetSeconds];
|
||||||
|
[aCoder encodeInt64:_kernelBootTime forKey:kGDTClockKernelBootTime];
|
||||||
|
[aCoder encodeInt64:_uptime forKey:kGDTClockUptime];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
36
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTConsoleLogger.m
generated
Normal file
36
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTConsoleLogger.m
generated
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Public/GDTConsoleLogger.h"
|
||||||
|
|
||||||
|
/** The console logger prefix. */
|
||||||
|
static NSString *kGDTConsoleLogger = @"[GoogleDataTransport]";
|
||||||
|
|
||||||
|
NSString *GDTMessageCodeEnumToString(GDTMessageCode code) {
|
||||||
|
return [[NSString alloc] initWithFormat:@"I-GDT%06ld", (long)code];
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDTLog(GDTMessageCode code, NSString *format, ...) {
|
||||||
|
// Don't log anything in not debug builds.
|
||||||
|
#ifndef NDEBUG
|
||||||
|
NSString *logFormat = [NSString
|
||||||
|
stringWithFormat:@"%@[%@] %@", kGDTConsoleLogger, GDTMessageCodeEnumToString(code), format];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
NSLogv(logFormat, args);
|
||||||
|
va_end(args);
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
64
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTDataFuture.m
generated
Normal file
64
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTDataFuture.m
generated
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTDataFuture.h>
|
||||||
|
|
||||||
|
@implementation GDTDataFuture
|
||||||
|
|
||||||
|
- (instancetype)initWithFileURL:(NSURL *)fileURL {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_fileURL = fileURL;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
return [self hash] == [object hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
// In reality, only one of these should be populated.
|
||||||
|
return [_fileURL hash] ^ [_originalData hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
/** Coding key for _fileURL ivar. */
|
||||||
|
static NSString *kGDTDataFutureFileURLKey = @"GDTDataFutureFileURLKey";
|
||||||
|
|
||||||
|
/** Coding key for _data ivar. */
|
||||||
|
static NSString *kGDTDataFutureDataKey = @"GDTDataFutureDataKey";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
|
||||||
|
[aCoder encodeObject:_fileURL forKey:kGDTDataFutureFileURLKey];
|
||||||
|
[aCoder encodeObject:_originalData forKey:kGDTDataFutureDataKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
|
||||||
|
self = [self init];
|
||||||
|
if (self) {
|
||||||
|
_fileURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kGDTDataFutureFileURLKey];
|
||||||
|
_originalData = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGDTDataFutureDataKey];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTEvent.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTEvent_Private.h"
|
||||||
|
|
||||||
|
@implementation GDTEvent
|
||||||
|
|
||||||
|
- (instancetype)initWithMappingID:(NSString *)mappingID target:(NSInteger)target {
|
||||||
|
GDTAssert(mappingID.length > 0, @"Please give a valid mapping ID");
|
||||||
|
GDTAssert(target > 0, @"A target cannot be negative or 0");
|
||||||
|
if (mappingID == nil || mappingID.length == 0 || target <= 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_mappingID = mappingID;
|
||||||
|
_target = target;
|
||||||
|
_qosTier = GDTEventQosDefault;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)copy {
|
||||||
|
GDTEvent *copy = [[GDTEvent alloc] initWithMappingID:_mappingID target:_target];
|
||||||
|
copy.dataObject = _dataObject;
|
||||||
|
copy.dataObjectTransportBytes = _dataObjectTransportBytes;
|
||||||
|
copy.qosTier = _qosTier;
|
||||||
|
copy.clockSnapshot = _clockSnapshot;
|
||||||
|
copy.customPrioritizationParams = _customPrioritizationParams;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
// This loses some precision, but it's probably fine.
|
||||||
|
NSUInteger mappingIDHash = [_mappingID hash];
|
||||||
|
NSUInteger timeHash = [_clockSnapshot hash];
|
||||||
|
NSUInteger dataObjectTransportBytesHash = [_dataObjectTransportBytes hash];
|
||||||
|
return mappingIDHash ^ _target ^ dataObjectTransportBytesHash ^ _qosTier ^ timeHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
return [self hash] == [object hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataObject:(id<GDTEventDataObject>)dataObject {
|
||||||
|
// If you're looking here because of a performance issue in -transportBytes slowing the assignment
|
||||||
|
// of -dataObject, one way to address this is to add a queue to this class,
|
||||||
|
// dispatch_(barrier_ if concurrent)async here, and implement the getter with a dispatch_sync.
|
||||||
|
if (dataObject != _dataObject) {
|
||||||
|
_dataObject = dataObject;
|
||||||
|
_dataObjectTransportBytes = [dataObject transportBytes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (GDTStoredEvent *)storedEventWithDataFuture:(GDTDataFuture *)dataFuture {
|
||||||
|
return [[GDTStoredEvent alloc] initWithEvent:self dataFuture:dataFuture];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding and NSCoding Protocols
|
||||||
|
|
||||||
|
/** NSCoding key for mappingID property. */
|
||||||
|
static NSString *mappingIDKey = @"_mappingID";
|
||||||
|
|
||||||
|
/** NSCoding key for target property. */
|
||||||
|
static NSString *targetKey = @"_target";
|
||||||
|
|
||||||
|
/** NSCoding key for dataObjectTransportBytes property. */
|
||||||
|
static NSString *dataObjectTransportBytesKey = @"_dataObjectTransportBytesKey";
|
||||||
|
|
||||||
|
/** NSCoding key for qosTier property. */
|
||||||
|
static NSString *qosTierKey = @"_qosTier";
|
||||||
|
|
||||||
|
/** NSCoding key for clockSnapshot property. */
|
||||||
|
static NSString *clockSnapshotKey = @"_clockSnapshot";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||||
|
NSString *mappingID = [aDecoder decodeObjectOfClass:[NSObject class] forKey:mappingIDKey];
|
||||||
|
NSInteger target = [aDecoder decodeIntegerForKey:targetKey];
|
||||||
|
self = [self initWithMappingID:mappingID target:target];
|
||||||
|
if (self) {
|
||||||
|
_dataObjectTransportBytes = [aDecoder decodeObjectOfClass:[NSData class]
|
||||||
|
forKey:dataObjectTransportBytesKey];
|
||||||
|
_qosTier = [aDecoder decodeIntegerForKey:qosTierKey];
|
||||||
|
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:clockSnapshotKey];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||||
|
[aCoder encodeObject:_mappingID forKey:mappingIDKey];
|
||||||
|
[aCoder encodeInteger:_target forKey:targetKey];
|
||||||
|
[aCoder encodeObject:_dataObjectTransportBytes forKey:dataObjectTransportBytesKey];
|
||||||
|
[aCoder encodeInteger:_qosTier forKey:qosTierKey];
|
||||||
|
[aCoder encodeObject:_clockSnapshot forKey:clockSnapshotKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
119
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTLifecycle.m
generated
Normal file
119
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTLifecycle.m
generated
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Public/GDTLifecycle.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTEvent.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTStorage_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTTransformer_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
|
||||||
|
|
||||||
|
@implementation GDTLifecycle
|
||||||
|
|
||||||
|
+ (void)load {
|
||||||
|
[self sharedInstance];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates/returns the singleton instance of this class.
|
||||||
|
*
|
||||||
|
* @return The singleton instance of this class.
|
||||||
|
*/
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTLifecycle *sharedInstance;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedInstance = [[GDTLifecycle alloc] init];
|
||||||
|
});
|
||||||
|
return sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(applicationDidEnterBackground:)
|
||||||
|
name:kGDTApplicationDidEnterBackgroundNotification
|
||||||
|
object:nil];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(applicationWillEnterForeground:)
|
||||||
|
name:kGDTApplicationWillEnterForegroundNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
NSString *name = kGDTApplicationWillTerminateNotification;
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(applicationWillTerminate:)
|
||||||
|
name:name
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidEnterBackground:(NSNotification *)notification {
|
||||||
|
GDTApplication *application = [GDTApplication sharedApplication];
|
||||||
|
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[[GDTTransformer sharedInstance] appWillBackground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[[GDTStorage sharedInstance] appWillBackground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[[GDTUploadCoordinator sharedInstance] appWillBackground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[[GDTRegistrar sharedInstance] appWillBackground:application];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillEnterForeground:(NSNotification *)notification {
|
||||||
|
GDTApplication *application = [GDTApplication sharedApplication];
|
||||||
|
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[[GDTTransformer sharedInstance] appWillForeground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[[GDTStorage sharedInstance] appWillForeground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[[GDTUploadCoordinator sharedInstance] appWillForeground:application];
|
||||||
|
}
|
||||||
|
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[[GDTRegistrar sharedInstance] appWillForeground:application];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(NSNotification *)notification {
|
||||||
|
GDTApplication *application = [GDTApplication sharedApplication];
|
||||||
|
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[[GDTTransformer sharedInstance] appWillTerminate:application];
|
||||||
|
}
|
||||||
|
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[[GDTStorage sharedInstance] appWillTerminate:application];
|
||||||
|
}
|
||||||
|
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[[GDTUploadCoordinator sharedInstance] appWillTerminate:application];
|
||||||
|
}
|
||||||
|
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[[GDTRegistrar sharedInstance] appWillTerminate:application];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTPlatform.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
|
||||||
|
const GDTBackgroundIdentifier GDTBackgroundIdentifierInvalid = 0;
|
||||||
|
|
||||||
|
NSString *const kGDTApplicationDidEnterBackgroundNotification =
|
||||||
|
@"GDTApplicationDidEnterBackgroundNotification";
|
||||||
|
|
||||||
|
NSString *const kGDTApplicationWillEnterForegroundNotification =
|
||||||
|
@"GDTApplicationWillEnterForegroundNotification";
|
||||||
|
|
||||||
|
NSString *const kGDTApplicationWillTerminateNotification =
|
||||||
|
@"GDTApplicationWillTerminateNotification";
|
||||||
|
|
||||||
|
BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN;
|
||||||
|
#else
|
||||||
|
return NO;
|
||||||
|
#endif // TARGET_OS_IOS
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation GDTApplication
|
||||||
|
|
||||||
|
+ (void)load {
|
||||||
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
// If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues.
|
||||||
|
GDTFatalAssert(GDTBackgroundIdentifierInvalid == UIBackgroundTaskInvalid,
|
||||||
|
@"GDTBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same.");
|
||||||
|
#endif
|
||||||
|
[self sharedApplication];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (nullable GDTApplication *)sharedApplication {
|
||||||
|
static GDTApplication *application;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
application = [[GDTApplication alloc] init];
|
||||||
|
});
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(iOSApplicationDidEnterBackground:)
|
||||||
|
name:UIApplicationDidEnterBackgroundNotification
|
||||||
|
object:nil];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(iOSApplicationWillEnterForeground:)
|
||||||
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
NSString *name = UIApplicationWillTerminateNotification;
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(iOSApplicationWillTerminate:)
|
||||||
|
name:name
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||||
|
if (@available(iOS 13, tvOS 13.0, *)) {
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(iOSApplicationWillEnterForeground:)
|
||||||
|
name:UISceneWillEnterForegroundNotification
|
||||||
|
object:nil];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(iOSApplicationDidEnterBackground:)
|
||||||
|
name:UISceneWillDeactivateNotification
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||||
|
|
||||||
|
#elif TARGET_OS_OSX
|
||||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notificationCenter addObserver:self
|
||||||
|
selector:@selector(macOSApplicationWillTerminate:)
|
||||||
|
name:NSApplicationWillTerminateNotification
|
||||||
|
object:nil];
|
||||||
|
#endif // TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (GDTBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
|
||||||
|
return
|
||||||
|
[[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithExpirationHandler:handler];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)endBackgroundTask:(GDTBackgroundIdentifier)bgID {
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - App environment helpers
|
||||||
|
|
||||||
|
- (BOOL)isAppExtension {
|
||||||
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
|
||||||
|
return appExtension;
|
||||||
|
#elif TARGET_OS_OSX
|
||||||
|
return NO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a UIApplication instance if on the appropriate platform.
|
||||||
|
*
|
||||||
|
* @return The shared UIApplication if on the appropriate platform.
|
||||||
|
*/
|
||||||
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
- (nullable UIApplication *)sharedApplicationForBackgroundTask {
|
||||||
|
#else
|
||||||
|
- (nullable id)sharedApplicationForBackgroundTask {
|
||||||
|
#endif
|
||||||
|
if ([self isAppExtension]) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
id sharedApplication = nil;
|
||||||
|
Class uiApplicationClass = NSClassFromString(@"UIApplication");
|
||||||
|
if (uiApplicationClass &&
|
||||||
|
[uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) {
|
||||||
|
sharedApplication = [uiApplicationClass sharedApplication];
|
||||||
|
}
|
||||||
|
return sharedApplication;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UIApplicationDelegate
|
||||||
|
|
||||||
|
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
- (void)iOSApplicationDidEnterBackground:(NSNotification *)notif {
|
||||||
|
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notifCenter postNotificationName:kGDTApplicationDidEnterBackgroundNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)iOSApplicationWillEnterForeground:(NSNotification *)notif {
|
||||||
|
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notifCenter postNotificationName:kGDTApplicationWillEnterForegroundNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)iOSApplicationWillTerminate:(NSNotification *)notif {
|
||||||
|
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notifCenter postNotificationName:kGDTApplicationWillTerminateNotification object:nil];
|
||||||
|
}
|
||||||
|
#endif // TARGET_OS_IOS || TARGET_OS_TV
|
||||||
|
|
||||||
|
#pragma mark - NSApplicationDelegate
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
- (void)macOSApplicationWillTerminate:(NSNotification *)notif {
|
||||||
|
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
|
||||||
|
[notifCenter postNotificationName:kGDTApplicationWillTerminateNotification object:nil];
|
||||||
|
}
|
||||||
|
#endif // TARGET_OS_OSX
|
||||||
|
|
||||||
|
@end
|
110
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTReachability.m
generated
Normal file
110
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTReachability.m
generated
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTReachability.h"
|
||||||
|
#import "GDTLibrary/Private/GDTReachability_Private.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
|
||||||
|
#import <netinet/in.h>
|
||||||
|
|
||||||
|
/** Sets the _callbackFlag ivar whenever the network changes.
|
||||||
|
*
|
||||||
|
* @param reachability The reachability object calling back.
|
||||||
|
* @param flags The new flag values.
|
||||||
|
* @param info Any data that might be passed in by the callback.
|
||||||
|
*/
|
||||||
|
static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
|
||||||
|
SCNetworkReachabilityFlags flags,
|
||||||
|
void *info);
|
||||||
|
|
||||||
|
@implementation GDTReachability {
|
||||||
|
/** The reachability object. */
|
||||||
|
SCNetworkReachabilityRef _reachabilityRef;
|
||||||
|
|
||||||
|
/** The queue on which callbacks and all work will occur. */
|
||||||
|
dispatch_queue_t _reachabilityQueue;
|
||||||
|
|
||||||
|
/** Flags specified by reachability callbacks. */
|
||||||
|
SCNetworkConnectionFlags _callbackFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)load {
|
||||||
|
[self sharedInstance];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTReachability *sharedInstance;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedInstance = [[GDTReachability alloc] init];
|
||||||
|
});
|
||||||
|
return sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SCNetworkReachabilityFlags)currentFlags {
|
||||||
|
__block SCNetworkReachabilityFlags currentFlags;
|
||||||
|
dispatch_sync([GDTReachability sharedInstance] -> _reachabilityQueue, ^{
|
||||||
|
GDTReachability *reachability = [GDTReachability sharedInstance];
|
||||||
|
currentFlags = reachability->_flags ? reachability->_flags : reachability->_callbackFlags;
|
||||||
|
});
|
||||||
|
return currentFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
struct sockaddr_in zeroAddress;
|
||||||
|
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||||
|
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||||
|
zeroAddress.sin_family = AF_INET;
|
||||||
|
|
||||||
|
_reachabilityQueue = dispatch_queue_create("com.google.GDTReachability", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_reachabilityRef = SCNetworkReachabilityCreateWithAddress(
|
||||||
|
kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
|
||||||
|
Boolean success = SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _reachabilityQueue);
|
||||||
|
if (!success) {
|
||||||
|
GDTLogWarning(GDTMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set.");
|
||||||
|
}
|
||||||
|
success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTReachabilityCallback, NULL);
|
||||||
|
if (!success) {
|
||||||
|
GDTLogWarning(GDTMCWReachabilityFailed, @"%@", @"The reachability callback wasn't set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the initial set of flags.
|
||||||
|
dispatch_async(_reachabilityQueue, ^{
|
||||||
|
Boolean valid = SCNetworkReachabilityGetFlags(self->_reachabilityRef, &self->_flags);
|
||||||
|
if (!valid) {
|
||||||
|
self->_flags = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setCallbackFlags:(SCNetworkReachabilityFlags)flags {
|
||||||
|
if (_callbackFlags != flags) {
|
||||||
|
self->_callbackFlags = flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
|
||||||
|
SCNetworkReachabilityFlags flags,
|
||||||
|
void *info) {
|
||||||
|
[[GDTReachability sharedInstance] setCallbackFlags:flags];
|
||||||
|
}
|
139
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTRegistrar.m
generated
Normal file
139
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTRegistrar.m
generated
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Public/GDTRegistrar.h"
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
|
||||||
|
|
||||||
|
@implementation GDTRegistrar {
|
||||||
|
/** Backing ivar for targetToUploader property. */
|
||||||
|
NSMutableDictionary<NSNumber *, id<GDTUploader>> *_targetToUploader;
|
||||||
|
|
||||||
|
/** Backing ivar for targetToPrioritizer property. */
|
||||||
|
NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *_targetToPrioritizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTRegistrar *sharedInstance;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedInstance = [[GDTRegistrar alloc] init];
|
||||||
|
});
|
||||||
|
return sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_registrarQueue = dispatch_queue_create("com.google.GDTRegistrar", DISPATCH_QUEUE_CONCURRENT);
|
||||||
|
_targetToPrioritizer = [[NSMutableDictionary alloc] init];
|
||||||
|
_targetToUploader = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerUploader:(id<GDTUploader>)backend target:(GDTTarget)target {
|
||||||
|
__weak GDTRegistrar *weakSelf = self;
|
||||||
|
dispatch_barrier_async(_registrarQueue, ^{
|
||||||
|
GDTRegistrar *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
strongSelf->_targetToUploader[@(target)] = backend;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerPrioritizer:(id<GDTPrioritizer>)prioritizer target:(GDTTarget)target {
|
||||||
|
__weak GDTRegistrar *weakSelf = self;
|
||||||
|
dispatch_barrier_async(_registrarQueue, ^{
|
||||||
|
GDTRegistrar *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
strongSelf->_targetToPrioritizer[@(target)] = prioritizer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary<NSNumber *, id<GDTUploader>> *)targetToUploader {
|
||||||
|
__block NSMutableDictionary<NSNumber *, id<GDTUploader>> *targetToUploader;
|
||||||
|
__weak GDTRegistrar *weakSelf = self;
|
||||||
|
dispatch_sync(_registrarQueue, ^{
|
||||||
|
GDTRegistrar *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
targetToUploader = strongSelf->_targetToUploader;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return targetToUploader;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *)targetToPrioritizer {
|
||||||
|
__block NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *targetToPrioritizer;
|
||||||
|
__weak GDTRegistrar *weakSelf = self;
|
||||||
|
dispatch_sync(_registrarQueue, ^{
|
||||||
|
GDTRegistrar *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
targetToPrioritizer = strongSelf->_targetToPrioritizer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return targetToPrioritizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - GDTLifecycleProtocol
|
||||||
|
|
||||||
|
- (void)appWillBackground:(nonnull GDTApplication *)app {
|
||||||
|
dispatch_async(_registrarQueue, ^{
|
||||||
|
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
|
||||||
|
if ([uploader respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[uploader appWillBackground:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
|
||||||
|
if ([prioritizer respondsToSelector:@selector(appWillBackground:)]) {
|
||||||
|
[prioritizer appWillBackground:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillForeground:(nonnull GDTApplication *)app {
|
||||||
|
dispatch_async(_registrarQueue, ^{
|
||||||
|
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
|
||||||
|
if ([uploader respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[uploader appWillForeground:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
|
||||||
|
if ([prioritizer respondsToSelector:@selector(appWillForeground:)]) {
|
||||||
|
[prioritizer appWillForeground:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillTerminate:(nonnull GDTApplication *)app {
|
||||||
|
dispatch_sync(_registrarQueue, ^{
|
||||||
|
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
|
||||||
|
if ([uploader respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[uploader appWillTerminate:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
|
||||||
|
if ([prioritizer respondsToSelector:@selector(appWillTerminate:)]) {
|
||||||
|
[prioritizer appWillTerminate:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,321 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTStorage.h"
|
||||||
|
#import "GDTLibrary/Private/GDTStorage_Private.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
#import <GoogleDataTransport/GDTLifecycle.h>
|
||||||
|
#import <GoogleDataTransport/GDTPrioritizer.h>
|
||||||
|
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTEvent_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
|
||||||
|
|
||||||
|
/** Creates and/or returns a singleton NSString that is the shared storage path.
|
||||||
|
*
|
||||||
|
* @return The SDK event storage path.
|
||||||
|
*/
|
||||||
|
static NSString *GDTStoragePath() {
|
||||||
|
static NSString *storagePath;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
NSString *cachePath =
|
||||||
|
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
|
||||||
|
storagePath = [NSString stringWithFormat:@"%@/google-sdks-events", cachePath];
|
||||||
|
});
|
||||||
|
return storagePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation GDTStorage
|
||||||
|
|
||||||
|
+ (NSString *)archivePath {
|
||||||
|
static NSString *archivePath;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
archivePath = [GDTStoragePath() stringByAppendingPathComponent:@"GDTStorageArchive"];
|
||||||
|
});
|
||||||
|
return archivePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTStorage *sharedStorage;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedStorage = [[GDTStorage alloc] init];
|
||||||
|
});
|
||||||
|
return sharedStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_storageQueue = dispatch_queue_create("com.google.GDTStorage", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_targetToEventSet = [[NSMutableDictionary alloc] init];
|
||||||
|
_storedEvents = [[NSMutableOrderedSet alloc] init];
|
||||||
|
_uploadCoordinator = [GDTUploadCoordinator sharedInstance];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)storeEvent:(GDTEvent *)event {
|
||||||
|
if (event == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self createEventDirectoryIfNotExists];
|
||||||
|
|
||||||
|
__block GDTBackgroundIdentifier bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
if (_runningInBackground) {
|
||||||
|
bgID = [[GDTApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_async(_storageQueue, ^{
|
||||||
|
// Check that a backend implementation is available for this target.
|
||||||
|
NSInteger target = event.target;
|
||||||
|
|
||||||
|
// Check that a prioritizer is available for this target.
|
||||||
|
id<GDTPrioritizer> prioritizer = [GDTRegistrar sharedInstance].targetToPrioritizer[@(target)];
|
||||||
|
GDTAssert(prioritizer, @"There's no prioritizer registered for the given target.");
|
||||||
|
|
||||||
|
// Write the transport bytes to disk, get a filename.
|
||||||
|
GDTAssert(event.dataObjectTransportBytes, @"The event should have been serialized to bytes");
|
||||||
|
NSURL *eventFile = [self saveEventBytesToDisk:event.dataObjectTransportBytes
|
||||||
|
eventHash:event.hash];
|
||||||
|
GDTDataFuture *dataFuture = [[GDTDataFuture alloc] initWithFileURL:eventFile];
|
||||||
|
GDTStoredEvent *storedEvent = [event storedEventWithDataFuture:dataFuture];
|
||||||
|
|
||||||
|
// Add event to tracking collections.
|
||||||
|
[self addEventToTrackingCollections:storedEvent];
|
||||||
|
|
||||||
|
// Have the prioritizer prioritize the event.
|
||||||
|
[prioritizer prioritizeEvent:storedEvent];
|
||||||
|
|
||||||
|
// Check the QoS, if it's high priority, notify the target that it has a high priority event.
|
||||||
|
if (event.qosTier == GDTEventQoSFast) {
|
||||||
|
[self.uploadCoordinator forceUploadForTarget:target];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write state to disk.
|
||||||
|
if (self->_runningInBackground) {
|
||||||
|
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
|
||||||
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
|
||||||
|
requiringSecureCoding:YES
|
||||||
|
error:nil];
|
||||||
|
[data writeToFile:[GDTStorage archivePath] atomically:YES];
|
||||||
|
} else {
|
||||||
|
#if !defined(TARGET_OS_MACCATALYST)
|
||||||
|
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If running in the background, save state to disk and end the associated background task.
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeEvents:(NSSet<GDTStoredEvent *> *)events {
|
||||||
|
NSSet<GDTStoredEvent *> *eventsToRemove = [events copy];
|
||||||
|
dispatch_async(_storageQueue, ^{
|
||||||
|
for (GDTStoredEvent *event in eventsToRemove) {
|
||||||
|
// Remove from disk, first and foremost.
|
||||||
|
NSError *error;
|
||||||
|
if (event.dataFuture.fileURL) {
|
||||||
|
NSURL *fileURL = event.dataFuture.fileURL;
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];
|
||||||
|
GDTAssert(error == nil, @"There was an error removing an event file: %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from the tracking collections.
|
||||||
|
[self.storedEvents removeObject:event];
|
||||||
|
[self.targetToEventSet[event.target] removeObject:event];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private helper methods
|
||||||
|
|
||||||
|
/** Creates the storage directory if it does not exist. */
|
||||||
|
- (void)createEventDirectoryIfNotExists {
|
||||||
|
NSError *error;
|
||||||
|
BOOL result = [[NSFileManager defaultManager] createDirectoryAtPath:GDTStoragePath()
|
||||||
|
withIntermediateDirectories:YES
|
||||||
|
attributes:0
|
||||||
|
error:&error];
|
||||||
|
if (!result || error) {
|
||||||
|
GDTLogError(GDTMCEDirectoryCreationError, @"Error creating the directory: %@", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Saves the event's dataObjectTransportBytes to a file using NSData mechanisms.
|
||||||
|
*
|
||||||
|
* @note This method should only be called from a method within a block on _storageQueue to maintain
|
||||||
|
* thread safety.
|
||||||
|
*
|
||||||
|
* @param transportBytes The transport bytes of the event.
|
||||||
|
* @param eventHash The hash value of the event.
|
||||||
|
* @return The filename
|
||||||
|
*/
|
||||||
|
- (NSURL *)saveEventBytesToDisk:(NSData *)transportBytes eventHash:(NSUInteger)eventHash {
|
||||||
|
NSString *storagePath = GDTStoragePath();
|
||||||
|
NSString *event = [NSString stringWithFormat:@"event-%lu", (unsigned long)eventHash];
|
||||||
|
NSURL *eventFilePath = [NSURL fileURLWithPath:[storagePath stringByAppendingPathComponent:event]];
|
||||||
|
|
||||||
|
GDTAssert(![[NSFileManager defaultManager] fileExistsAtPath:eventFilePath.path],
|
||||||
|
@"An event shouldn't already exist at this path: %@", eventFilePath.path);
|
||||||
|
|
||||||
|
BOOL writingSuccess = [transportBytes writeToURL:eventFilePath atomically:YES];
|
||||||
|
if (!writingSuccess) {
|
||||||
|
GDTLogError(GDTMCEFileWriteError, @"An event file could not be written: %@", eventFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds the event to internal tracking collections.
|
||||||
|
*
|
||||||
|
* @note This method should only be called from a method within a block on _storageQueue to maintain
|
||||||
|
* thread safety.
|
||||||
|
*
|
||||||
|
* @param event The event to track.
|
||||||
|
*/
|
||||||
|
- (void)addEventToTrackingCollections:(GDTStoredEvent *)event {
|
||||||
|
[_storedEvents addObject:event];
|
||||||
|
NSMutableSet<GDTStoredEvent *> *events = self.targetToEventSet[event.target];
|
||||||
|
events = events ? events : [[NSMutableSet alloc] init];
|
||||||
|
[events addObject:event];
|
||||||
|
_targetToEventSet[event.target] = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - GDTLifecycleProtocol
|
||||||
|
|
||||||
|
- (void)appWillForeground:(GDTApplication *)app {
|
||||||
|
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
|
||||||
|
NSData *data = [NSData dataWithContentsOfFile:[GDTStorage archivePath]];
|
||||||
|
[NSKeyedUnarchiver unarchivedObjectOfClass:[GDTStorage class] fromData:data error:nil];
|
||||||
|
} else {
|
||||||
|
#if !defined(TARGET_OS_MACCATALYST)
|
||||||
|
[NSKeyedUnarchiver unarchiveObjectWithFile:[GDTStorage archivePath]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillBackground:(GDTApplication *)app {
|
||||||
|
self->_runningInBackground = YES;
|
||||||
|
dispatch_async(_storageQueue, ^{
|
||||||
|
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
|
||||||
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
|
||||||
|
requiringSecureCoding:YES
|
||||||
|
error:nil];
|
||||||
|
[data writeToFile:[GDTStorage archivePath] atomically:YES];
|
||||||
|
} else {
|
||||||
|
#if !defined(TARGET_OS_MACCATALYST)
|
||||||
|
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create an immediate background task to run until the end of the current queue of work.
|
||||||
|
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
dispatch_async(_storageQueue, ^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillTerminate:(GDTApplication *)application {
|
||||||
|
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
|
||||||
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
|
||||||
|
requiringSecureCoding:YES
|
||||||
|
error:nil];
|
||||||
|
[data writeToFile:[GDTStorage archivePath] atomically:YES];
|
||||||
|
} else {
|
||||||
|
#if !defined(TARGET_OS_MACCATALYST)
|
||||||
|
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
/** The NSKeyedCoder key for the storedEvents property. */
|
||||||
|
static NSString *const kGDTStorageStoredEventsKey = @"GDTStorageStoredEventsKey";
|
||||||
|
|
||||||
|
/** The NSKeyedCoder key for the targetToEventSet property. */
|
||||||
|
static NSString *const kGDTStorageTargetToEventSetKey = @"GDTStorageTargetToEventSetKey";
|
||||||
|
|
||||||
|
/** The NSKeyedCoder key for the uploadCoordinator property. */
|
||||||
|
static NSString *const kGDTStorageUploadCoordinatorKey = @"GDTStorageUploadCoordinatorKey";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||||
|
// Create the singleton and populate its ivars.
|
||||||
|
GDTStorage *sharedInstance = [self.class sharedInstance];
|
||||||
|
dispatch_sync(sharedInstance.storageQueue, ^{
|
||||||
|
NSSet *classes =
|
||||||
|
[NSSet setWithObjects:[NSMutableOrderedSet class], [GDTStoredEvent class], nil];
|
||||||
|
sharedInstance->_storedEvents = [aDecoder decodeObjectOfClasses:classes
|
||||||
|
forKey:kGDTStorageStoredEventsKey];
|
||||||
|
classes = [NSSet setWithObjects:[NSMutableDictionary class], [NSMutableSet class],
|
||||||
|
[GDTStoredEvent class], nil];
|
||||||
|
sharedInstance->_targetToEventSet =
|
||||||
|
[aDecoder decodeObjectOfClasses:classes forKey:kGDTStorageTargetToEventSetKey];
|
||||||
|
sharedInstance->_uploadCoordinator =
|
||||||
|
[aDecoder decodeObjectOfClass:[GDTUploadCoordinator class]
|
||||||
|
forKey:kGDTStorageUploadCoordinatorKey];
|
||||||
|
});
|
||||||
|
return sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||||
|
GDTStorage *sharedInstance = [self.class sharedInstance];
|
||||||
|
NSMutableOrderedSet<GDTStoredEvent *> *storedEvents = sharedInstance->_storedEvents;
|
||||||
|
if (storedEvents) {
|
||||||
|
[aCoder encodeObject:storedEvents forKey:kGDTStorageStoredEventsKey];
|
||||||
|
}
|
||||||
|
NSMutableDictionary<NSNumber *, NSMutableSet<GDTStoredEvent *> *> *targetToEventSet =
|
||||||
|
sharedInstance->_targetToEventSet;
|
||||||
|
if (targetToEventSet) {
|
||||||
|
[aCoder encodeObject:targetToEventSet forKey:kGDTStorageTargetToEventSetKey];
|
||||||
|
}
|
||||||
|
GDTUploadCoordinator *uploadCoordinator = sharedInstance->_uploadCoordinator;
|
||||||
|
if (uploadCoordinator) {
|
||||||
|
[aCoder encodeObject:uploadCoordinator forKey:kGDTStorageUploadCoordinatorKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
94
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m
generated
Normal file
94
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m
generated
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTClock.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTStorage_Private.h"
|
||||||
|
|
||||||
|
@implementation GDTStoredEvent
|
||||||
|
|
||||||
|
- (instancetype)initWithEvent:(GDTEvent *)event dataFuture:(nonnull GDTDataFuture *)dataFuture {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_dataFuture = dataFuture;
|
||||||
|
_mappingID = event.mappingID;
|
||||||
|
_target = @(event.target);
|
||||||
|
_qosTier = event.qosTier;
|
||||||
|
_clockSnapshot = event.clockSnapshot;
|
||||||
|
_customPrioritizationParams = event.customPrioritizationParams;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
/** Coding key for the dataFuture ivar. */
|
||||||
|
static NSString *kDataFutureKey = @"GDTStoredEventDataFutureKey";
|
||||||
|
|
||||||
|
/** Coding key for mappingID ivar. */
|
||||||
|
static NSString *kMappingIDKey = @"GDTStoredEventMappingIDKey";
|
||||||
|
|
||||||
|
/** Coding key for target ivar. */
|
||||||
|
static NSString *kTargetKey = @"GDTStoredEventTargetKey";
|
||||||
|
|
||||||
|
/** Coding key for qosTier ivar. */
|
||||||
|
static NSString *kQosTierKey = @"GDTStoredEventQosTierKey";
|
||||||
|
|
||||||
|
/** Coding key for clockSnapshot ivar. */
|
||||||
|
static NSString *kClockSnapshotKey = @"GDTStoredEventClockSnapshotKey";
|
||||||
|
|
||||||
|
/** Coding key for customPrioritizationParams ivar. */
|
||||||
|
static NSString *kCustomPrioritizationParamsKey = @"GDTStoredEventcustomPrioritizationParamsKey";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
|
||||||
|
[aCoder encodeObject:_dataFuture forKey:kDataFutureKey];
|
||||||
|
[aCoder encodeObject:_mappingID forKey:kMappingIDKey];
|
||||||
|
[aCoder encodeObject:_target forKey:kTargetKey];
|
||||||
|
[aCoder encodeObject:@(_qosTier) forKey:kQosTierKey];
|
||||||
|
[aCoder encodeObject:_clockSnapshot forKey:kClockSnapshotKey];
|
||||||
|
[aCoder encodeObject:_customPrioritizationParams forKey:kCustomPrioritizationParamsKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
|
||||||
|
self = [self init];
|
||||||
|
if (self) {
|
||||||
|
_dataFuture = [aDecoder decodeObjectOfClass:[GDTDataFuture class] forKey:kDataFutureKey];
|
||||||
|
_mappingID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kMappingIDKey];
|
||||||
|
_target = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kTargetKey];
|
||||||
|
NSNumber *qosTier = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kQosTierKey];
|
||||||
|
_qosTier = [qosTier intValue];
|
||||||
|
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:kClockSnapshotKey];
|
||||||
|
_customPrioritizationParams = [aDecoder decodeObjectOfClass:[NSDictionary class]
|
||||||
|
forKey:kCustomPrioritizationParamsKey];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(GDTStoredEvent *)other {
|
||||||
|
return [self hash] == [other hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
return [_dataFuture hash] ^ [_mappingID hash] ^ [_target hash] ^ [_clockSnapshot hash] ^ _qosTier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
112
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTTransformer.m
generated
Normal file
112
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTTransformer.m
generated
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTTransformer.h"
|
||||||
|
#import "GDTLibrary/Private/GDTTransformer_Private.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
#import <GoogleDataTransport/GDTEventTransformer.h>
|
||||||
|
#import <GoogleDataTransport/GDTLifecycle.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTStorage.h"
|
||||||
|
|
||||||
|
@implementation GDTTransformer
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTTransformer *eventTransformer;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
eventTransformer = [[self alloc] init];
|
||||||
|
});
|
||||||
|
return eventTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_eventWritingQueue = dispatch_queue_create("com.google.GDTTransformer", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_storageInstance = [GDTStorage sharedInstance];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)transformEvent:(GDTEvent *)event
|
||||||
|
withTransformers:(NSArray<id<GDTEventTransformer>> *)transformers {
|
||||||
|
GDTAssert(event, @"You can't write a nil event");
|
||||||
|
|
||||||
|
__block GDTBackgroundIdentifier bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
if (_runningInBackground) {
|
||||||
|
bgID = [[GDTApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
dispatch_async(_eventWritingQueue, ^{
|
||||||
|
GDTEvent *transformedEvent = event;
|
||||||
|
for (id<GDTEventTransformer> transformer in transformers) {
|
||||||
|
if ([transformer respondsToSelector:@selector(transform:)]) {
|
||||||
|
transformedEvent = [transformer transform:transformedEvent];
|
||||||
|
if (!transformedEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GDTLogError(GDTMCETransformerDoesntImplementTransform,
|
||||||
|
@"Transformer doesn't implement transform: %@", transformer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self.storageInstance storeEvent:transformedEvent];
|
||||||
|
if (self->_runningInBackground) {
|
||||||
|
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - GDTLifecycleProtocol
|
||||||
|
|
||||||
|
- (void)appWillForeground:(GDTApplication *)app {
|
||||||
|
dispatch_async(_eventWritingQueue, ^{
|
||||||
|
self->_runningInBackground = NO;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillBackground:(GDTApplication *)app {
|
||||||
|
// Create an immediate background task to run until the end of the current queue of work.
|
||||||
|
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
dispatch_async(_eventWritingQueue, ^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillTerminate:(GDTApplication *)application {
|
||||||
|
// Flush the queue immediately.
|
||||||
|
dispatch_sync(_eventWritingQueue, ^{
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTTransport.h>
|
||||||
|
#import "GDTLibrary/Private/GDTTransport_Private.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
#import <GoogleDataTransport/GDTClock.h>
|
||||||
|
#import <GoogleDataTransport/GDTEvent.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTTransformer.h"
|
||||||
|
|
||||||
|
@implementation GDTTransport
|
||||||
|
|
||||||
|
- (instancetype)initWithMappingID:(NSString *)mappingID
|
||||||
|
transformers:(nullable NSArray<id<GDTEventTransformer>> *)transformers
|
||||||
|
target:(NSInteger)target {
|
||||||
|
GDTAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty");
|
||||||
|
GDTAssert(target > 0, @"A target cannot be negative or 0");
|
||||||
|
if (mappingID == nil || mappingID.length == 0 || target <= 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_mappingID = mappingID;
|
||||||
|
_transformers = transformers;
|
||||||
|
_target = target;
|
||||||
|
_transformerInstance = [GDTTransformer sharedInstance];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendTelemetryEvent:(GDTEvent *)event {
|
||||||
|
// TODO: Determine if sending an event before registration is allowed.
|
||||||
|
GDTAssert(event, @"You can't send a nil event");
|
||||||
|
GDTEvent *copiedEvent = [event copy];
|
||||||
|
copiedEvent.qosTier = GDTEventQoSTelemetry;
|
||||||
|
copiedEvent.clockSnapshot = [GDTClock snapshot];
|
||||||
|
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendDataEvent:(GDTEvent *)event {
|
||||||
|
// TODO: Determine if sending an event before registration is allowed.
|
||||||
|
GDTAssert(event, @"You can't send a nil event");
|
||||||
|
GDTAssert(event.qosTier != GDTEventQoSTelemetry, @"Use -sendTelemetryEvent, please.");
|
||||||
|
GDTEvent *copiedEvent = [event copy];
|
||||||
|
copiedEvent.clockSnapshot = [GDTClock snapshot];
|
||||||
|
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (GDTEvent *)eventForTransport {
|
||||||
|
return [[GDTEvent alloc] initWithMappingID:_mappingID target:_target];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
274
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTUploadCoordinator.m
generated
Normal file
274
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTUploadCoordinator.m
generated
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTAssert.h>
|
||||||
|
#import <GoogleDataTransport/GDTClock.h>
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTReachability.h"
|
||||||
|
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTStorage.h"
|
||||||
|
|
||||||
|
@implementation GDTUploadCoordinator
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static GDTUploadCoordinator *sharedUploader;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
sharedUploader = [[GDTUploadCoordinator alloc] init];
|
||||||
|
[sharedUploader startTimer];
|
||||||
|
});
|
||||||
|
return sharedUploader;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_coordinationQueue =
|
||||||
|
dispatch_queue_create("com.google.GDTUploadCoordinator", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_registrar = [GDTRegistrar sharedInstance];
|
||||||
|
_timerInterval = 30 * NSEC_PER_SEC;
|
||||||
|
_timerLeeway = 5 * NSEC_PER_SEC;
|
||||||
|
_targetToInFlightPackages = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)forceUploadForTarget:(GDTTarget)target {
|
||||||
|
dispatch_async(_coordinationQueue, ^{
|
||||||
|
GDTUploadConditions conditions = [self uploadConditions];
|
||||||
|
conditions |= GDTUploadConditionHighPriority;
|
||||||
|
[self uploadTargets:@[ @(target) ] conditions:conditions];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Property overrides
|
||||||
|
|
||||||
|
// GDTStorage and GDTUploadCoordinator +sharedInstance methods call each other, so this breaks
|
||||||
|
// the loop.
|
||||||
|
- (GDTStorage *)storage {
|
||||||
|
if (!_storage) {
|
||||||
|
_storage = [GDTStorage sharedInstance];
|
||||||
|
}
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private helper methods
|
||||||
|
|
||||||
|
/** Starts a timer that checks whether or not events can be uploaded at regular intervals. It will
|
||||||
|
* check the next-upload clocks of all targets to determine if an upload attempt can be made.
|
||||||
|
*/
|
||||||
|
- (void)startTimer {
|
||||||
|
dispatch_sync(_coordinationQueue, ^{
|
||||||
|
self->_timer =
|
||||||
|
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self->_coordinationQueue);
|
||||||
|
dispatch_source_set_timer(self->_timer, DISPATCH_TIME_NOW, self->_timerInterval,
|
||||||
|
self->_timerLeeway);
|
||||||
|
dispatch_source_set_event_handler(self->_timer, ^{
|
||||||
|
if (!self->_runningInBackground) {
|
||||||
|
GDTUploadConditions conditions = [self uploadConditions];
|
||||||
|
[self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dispatch_resume(self->_timer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stops the currently running timer. */
|
||||||
|
- (void)stopTimer {
|
||||||
|
if (_timer) {
|
||||||
|
dispatch_source_cancel(_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Triggers the uploader implementations for the given targets to upload.
|
||||||
|
*
|
||||||
|
* @param targets An array of targets to trigger.
|
||||||
|
* @param conditions The set of upload conditions.
|
||||||
|
*/
|
||||||
|
- (void)uploadTargets:(NSArray<NSNumber *> *)targets conditions:(GDTUploadConditions)conditions {
|
||||||
|
dispatch_async(_coordinationQueue, ^{
|
||||||
|
if ((conditions & GDTUploadConditionNoNetwork) == GDTUploadConditionNoNetwork) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (NSNumber *target in targets) {
|
||||||
|
// Don't trigger uploads for targets that have an in-flight package already.
|
||||||
|
if (self->_targetToInFlightPackages[target]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Ask the uploader if they can upload and do so, if it can.
|
||||||
|
id<GDTUploader> uploader = self.registrar.targetToUploader[target];
|
||||||
|
if ([uploader readyToUploadWithConditions:conditions]) {
|
||||||
|
id<GDTPrioritizer> prioritizer = self.registrar.targetToPrioritizer[target];
|
||||||
|
GDTUploadPackage *package = [prioritizer uploadPackageWithConditions:conditions];
|
||||||
|
if (package.events.count) {
|
||||||
|
self->_targetToInFlightPackages[target] = package;
|
||||||
|
[uploader uploadPackage:package];
|
||||||
|
} else {
|
||||||
|
[package completeDelivery];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current upload conditions after making determinations about the network connection.
|
||||||
|
*
|
||||||
|
* @return The current upload conditions.
|
||||||
|
*/
|
||||||
|
- (GDTUploadConditions)uploadConditions {
|
||||||
|
SCNetworkReachabilityFlags currentFlags = [GDTReachability currentFlags];
|
||||||
|
BOOL reachable =
|
||||||
|
(currentFlags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable;
|
||||||
|
BOOL connectionRequired = (currentFlags & kSCNetworkReachabilityFlagsConnectionRequired) ==
|
||||||
|
kSCNetworkReachabilityFlagsConnectionRequired;
|
||||||
|
BOOL networkConnected = reachable && !connectionRequired;
|
||||||
|
|
||||||
|
if (!networkConnected) {
|
||||||
|
return GDTUploadConditionNoNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL isWWAN = GDTReachabilityFlagsContainWWAN(currentFlags);
|
||||||
|
if (isWWAN) {
|
||||||
|
return GDTUploadConditionMobileData;
|
||||||
|
} else {
|
||||||
|
return GDTUploadConditionWifiData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding support
|
||||||
|
|
||||||
|
/** The NSKeyedCoder key for the targetToInFlightPackages property. */
|
||||||
|
static NSString *const ktargetToInFlightPackagesKey =
|
||||||
|
@"GDTUploadCoordinatortargetToInFlightPackages";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||||
|
GDTUploadCoordinator *sharedCoordinator = [GDTUploadCoordinator sharedInstance];
|
||||||
|
@try {
|
||||||
|
sharedCoordinator->_targetToInFlightPackages =
|
||||||
|
[aDecoder decodeObjectOfClass:[NSMutableDictionary class]
|
||||||
|
forKey:ktargetToInFlightPackagesKey];
|
||||||
|
|
||||||
|
} @catch (NSException *exception) {
|
||||||
|
sharedCoordinator->_targetToInFlightPackages = [NSMutableDictionary dictionary];
|
||||||
|
}
|
||||||
|
return sharedCoordinator;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||||
|
// All packages that have been given to uploaders need to be tracked so that their expiration
|
||||||
|
// timers can be called.
|
||||||
|
if (_targetToInFlightPackages.count > 0) {
|
||||||
|
[aCoder encodeObject:_targetToInFlightPackages forKey:ktargetToInFlightPackagesKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - GDTLifecycleProtocol
|
||||||
|
|
||||||
|
- (void)appWillForeground:(GDTApplication *)app {
|
||||||
|
// Not entirely thread-safe, but it should be fine.
|
||||||
|
self->_runningInBackground = NO;
|
||||||
|
[self startTimer];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillBackground:(GDTApplication *)app {
|
||||||
|
// Not entirely thread-safe, but it should be fine.
|
||||||
|
self->_runningInBackground = YES;
|
||||||
|
|
||||||
|
// Should be thread-safe. If it ends up not being, put this in a dispatch_sync.
|
||||||
|
[self stopTimer];
|
||||||
|
|
||||||
|
// Create an immediate background task to run until the end of the current queue of work.
|
||||||
|
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
dispatch_async(_coordinationQueue, ^{
|
||||||
|
if (bgID != GDTBackgroundIdentifierInvalid) {
|
||||||
|
[app endBackgroundTask:bgID];
|
||||||
|
bgID = GDTBackgroundIdentifierInvalid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appWillTerminate:(GDTApplication *)application {
|
||||||
|
dispatch_sync(_coordinationQueue, ^{
|
||||||
|
[self stopTimer];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - GDTUploadPackageProtocol
|
||||||
|
|
||||||
|
- (void)packageDelivered:(GDTUploadPackage *)package successful:(BOOL)successful {
|
||||||
|
if (!_coordinationQueue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(_coordinationQueue, ^{
|
||||||
|
NSNumber *targetNumber = @(package.target);
|
||||||
|
NSMutableDictionary<NSNumber *, GDTUploadPackage *> *targetToInFlightPackages =
|
||||||
|
self->_targetToInFlightPackages;
|
||||||
|
GDTRegistrar *registrar = self->_registrar;
|
||||||
|
if (targetToInFlightPackages) {
|
||||||
|
[targetToInFlightPackages removeObjectForKey:targetNumber];
|
||||||
|
}
|
||||||
|
if (registrar) {
|
||||||
|
id<GDTPrioritizer> prioritizer = registrar.targetToPrioritizer[targetNumber];
|
||||||
|
if (!prioritizer) {
|
||||||
|
GDTLogError(GDTMCEPrioritizerError,
|
||||||
|
@"A prioritizer should be registered for this target: %@", targetNumber);
|
||||||
|
}
|
||||||
|
if ([prioritizer respondsToSelector:@selector(packageDelivered:successful:)]) {
|
||||||
|
[prioritizer packageDelivered:package successful:successful];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self.storage removeEvents:package.events];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)packageExpired:(GDTUploadPackage *)package {
|
||||||
|
if (!_coordinationQueue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(_coordinationQueue, ^{
|
||||||
|
NSNumber *targetNumber = @(package.target);
|
||||||
|
NSMutableDictionary<NSNumber *, GDTUploadPackage *> *targetToInFlightPackages =
|
||||||
|
self->_targetToInFlightPackages;
|
||||||
|
GDTRegistrar *registrar = self->_registrar;
|
||||||
|
if (targetToInFlightPackages) {
|
||||||
|
[targetToInFlightPackages removeObjectForKey:targetNumber];
|
||||||
|
}
|
||||||
|
if (registrar) {
|
||||||
|
id<GDTPrioritizer> prioritizer = registrar.targetToPrioritizer[targetNumber];
|
||||||
|
id<GDTUploader> uploader = registrar.targetToUploader[targetNumber];
|
||||||
|
if ([prioritizer respondsToSelector:@selector(packageExpired:)]) {
|
||||||
|
[prioritizer packageExpired:package];
|
||||||
|
}
|
||||||
|
if ([uploader respondsToSelector:@selector(packageExpired:)]) {
|
||||||
|
[uploader packageExpired:package];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
154
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTUploadPackage.m
generated
Normal file
154
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/GDTUploadPackage.m
generated
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTUploadPackage.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTClock.h>
|
||||||
|
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||||
|
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTStorage_Private.h"
|
||||||
|
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
|
||||||
|
#import "GDTLibrary/Private/GDTUploadPackage_Private.h"
|
||||||
|
|
||||||
|
@implementation GDTUploadPackage {
|
||||||
|
/** If YES, the package's -completeDelivery method has been called. */
|
||||||
|
BOOL _isDelivered;
|
||||||
|
|
||||||
|
/** If YES, is being handled by the handler. */
|
||||||
|
BOOL _isHandled;
|
||||||
|
|
||||||
|
/** A timer that will regularly check to see whether this package has expired or not. */
|
||||||
|
NSTimer *_expirationTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithTarget:(GDTTarget)target {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_target = target;
|
||||||
|
_storage = [GDTStorage sharedInstance];
|
||||||
|
_deliverByTime = [GDTClock clockSnapshotInTheFuture:180000];
|
||||||
|
_handler = [GDTUploadCoordinator sharedInstance];
|
||||||
|
_expirationTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
|
||||||
|
target:self
|
||||||
|
selector:@selector(checkIfPackageIsExpired:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)copy {
|
||||||
|
GDTUploadPackage *newPackage = [[GDTUploadPackage alloc] initWithTarget:_target];
|
||||||
|
newPackage->_events = [_events copy];
|
||||||
|
return newPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
return [_events hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
return [self hash] == [object hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_expirationTimer invalidate];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setStorage:(GDTStorage *)storage {
|
||||||
|
if (storage != _storage) {
|
||||||
|
_storage = storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)completeDelivery {
|
||||||
|
if (_isDelivered) {
|
||||||
|
GDTLogError(GDTMCEDeliverTwice, @"%@",
|
||||||
|
@"It's an API violation to call -completeDelivery twice.");
|
||||||
|
}
|
||||||
|
_isDelivered = YES;
|
||||||
|
if (!_isHandled && _handler &&
|
||||||
|
[_handler respondsToSelector:@selector(packageDelivered:successful:)]) {
|
||||||
|
[_expirationTimer invalidate];
|
||||||
|
_isHandled = YES;
|
||||||
|
[_handler packageDelivered:self successful:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)retryDeliveryInTheFuture {
|
||||||
|
if (!_isHandled && _handler &&
|
||||||
|
[_handler respondsToSelector:@selector(packageDelivered:successful:)]) {
|
||||||
|
[_expirationTimer invalidate];
|
||||||
|
_isHandled = YES;
|
||||||
|
[_handler packageDelivered:self successful:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)checkIfPackageIsExpired:(NSTimer *)timer {
|
||||||
|
if ([[GDTClock snapshot] isAfter:_deliverByTime]) {
|
||||||
|
if (_handler && [_handler respondsToSelector:@selector(packageExpired:)]) {
|
||||||
|
_isHandled = YES;
|
||||||
|
[_expirationTimer invalidate];
|
||||||
|
[_handler packageExpired:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
/** The keyed archiver key for the events property. */
|
||||||
|
static NSString *const kEventsKey = @"GDTUploadPackageEventsKey";
|
||||||
|
|
||||||
|
/** The keyed archiver key for the _isHandled property. */
|
||||||
|
static NSString *const kDeliverByTimeKey = @"GDTUploadPackageDeliveryByTimeKey";
|
||||||
|
|
||||||
|
/** The keyed archiver key for the _isHandled ivar. */
|
||||||
|
static NSString *const kIsHandledKey = @"GDTUploadPackageIsHandledKey";
|
||||||
|
|
||||||
|
/** The keyed archiver key for the handler property. */
|
||||||
|
static NSString *const kHandlerKey = @"GDTUploadPackageHandlerKey";
|
||||||
|
|
||||||
|
/** The keyed archiver key for the target property. */
|
||||||
|
static NSString *const kTargetKey = @"GDTUploadPackageTargetKey";
|
||||||
|
|
||||||
|
+ (BOOL)supportsSecureCoding {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
|
||||||
|
[aCoder encodeObject:_events forKey:kEventsKey];
|
||||||
|
[aCoder encodeObject:_deliverByTime forKey:kDeliverByTimeKey];
|
||||||
|
[aCoder encodeBool:_isHandled forKey:kIsHandledKey];
|
||||||
|
[aCoder encodeObject:_handler forKey:kHandlerKey];
|
||||||
|
[aCoder encodeInteger:_target forKey:kTargetKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
|
||||||
|
GDTTarget target = [aDecoder decodeIntegerForKey:kTargetKey];
|
||||||
|
self = [self initWithTarget:target];
|
||||||
|
if (self) {
|
||||||
|
NSSet *classes = [NSSet setWithObjects:[NSSet class], [GDTStoredEvent class], nil];
|
||||||
|
_events = [aDecoder decodeObjectOfClasses:classes forKey:kEventsKey];
|
||||||
|
_deliverByTime = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:kDeliverByTimeKey];
|
||||||
|
_isHandled = [aDecoder decodeBoolForKey:kIsHandledKey];
|
||||||
|
// _handler isn't technically NSSecureCoding, because we don't know the class of this object.
|
||||||
|
// but it gets decoded anyway.
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
30
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTEvent_Private.h
generated
Normal file
30
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTEvent_Private.h
generated
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTEvent.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTClock.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface GDTEvent ()
|
||||||
|
|
||||||
|
/** The serialized bytes of the event data object. */
|
||||||
|
@property(nonatomic) NSData *dataObjectTransportBytes;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
31
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTReachability.h
generated
Normal file
31
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTReachability.h
generated
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <SystemConfiguration/SCNetworkReachability.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** This class helps determine upload conditions by determining connectivity. */
|
||||||
|
@interface GDTReachability : NSObject
|
||||||
|
|
||||||
|
/** The current set flags indicating network conditions */
|
||||||
|
+ (SCNetworkReachabilityFlags)currentFlags;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
30
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTReachability_Private.h
generated
Normal file
30
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTReachability_Private.h
generated
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTReachability.h"
|
||||||
|
|
||||||
|
@interface GDTReachability ()
|
||||||
|
|
||||||
|
/** Allows manually setting the flags for testing purposes. */
|
||||||
|
@property(nonatomic, readwrite) SCNetworkReachabilityFlags flags;
|
||||||
|
|
||||||
|
/** Creates/returns the singleton instance of this class.
|
||||||
|
*
|
||||||
|
* @return The singleton instance of this class.
|
||||||
|
*/
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
@end
|
35
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTRegistrar_Private.h
generated
Normal file
35
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTRegistrar_Private.h
generated
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTRegistrar.h>
|
||||||
|
|
||||||
|
@interface GDTRegistrar ()
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** The concurrent queue on which all registration occurs. */
|
||||||
|
@property(nonatomic, readonly) dispatch_queue_t registrarQueue;
|
||||||
|
|
||||||
|
/** A map of targets to backend implementations. */
|
||||||
|
@property(atomic, readonly) NSMutableDictionary<NSNumber *, id<GDTUploader>> *targetToUploader;
|
||||||
|
|
||||||
|
/** A map of targets to prioritizer implementations. */
|
||||||
|
@property(atomic, readonly)
|
||||||
|
NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *targetToPrioritizer;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
50
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTStorage.h
generated
Normal file
50
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTStorage.h
generated
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTLifecycle.h>
|
||||||
|
|
||||||
|
@class GDTEvent;
|
||||||
|
@class GDTStoredEvent;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** Manages the storage of events. This class is thread-safe. */
|
||||||
|
@interface GDTStorage : NSObject <NSSecureCoding, GDTLifecycleProtocol>
|
||||||
|
|
||||||
|
/** Creates and/or returns the storage singleton.
|
||||||
|
*
|
||||||
|
* @return The storage singleton.
|
||||||
|
*/
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
/** Stores event.dataObjectTransportBytes into a shared on-device folder and tracks the event via
|
||||||
|
* a GDTStoredEvent instance.
|
||||||
|
*
|
||||||
|
* @param event The event to store.
|
||||||
|
*/
|
||||||
|
- (void)storeEvent:(GDTEvent *)event;
|
||||||
|
|
||||||
|
/** Removes a set of events from storage specified by their hash.
|
||||||
|
*
|
||||||
|
* @param events The set of stored events to remove.
|
||||||
|
*/
|
||||||
|
- (void)removeEvents:(NSSet<GDTStoredEvent *> *)events;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
51
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTStorage_Private.h
generated
Normal file
51
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTStorage_Private.h
generated
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTStorage.h"
|
||||||
|
|
||||||
|
@class GDTUploadCoordinator;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface GDTStorage ()
|
||||||
|
|
||||||
|
/** The queue on which all storage work will occur. */
|
||||||
|
@property(nonatomic) dispatch_queue_t storageQueue;
|
||||||
|
|
||||||
|
/** A map of targets to a set of stored events. */
|
||||||
|
@property(nonatomic)
|
||||||
|
NSMutableDictionary<NSNumber *, NSMutableSet<GDTStoredEvent *> *> *targetToEventSet;
|
||||||
|
|
||||||
|
/** All the events that have been stored. */
|
||||||
|
@property(readonly, nonatomic) NSMutableOrderedSet<GDTStoredEvent *> *storedEvents;
|
||||||
|
|
||||||
|
/** The upload coordinator instance used by this storage instance. */
|
||||||
|
@property(nonatomic) GDTUploadCoordinator *uploadCoordinator;
|
||||||
|
|
||||||
|
/** If YES, every call to -storeLog results in background task and serializes the singleton to disk.
|
||||||
|
*/
|
||||||
|
@property(nonatomic) BOOL runningInBackground;
|
||||||
|
|
||||||
|
/** Returns the path to the keyed archive of the singleton. This is where the singleton is saved
|
||||||
|
* to disk during certain app lifecycle events.
|
||||||
|
*
|
||||||
|
* @return File path to serialized singleton.
|
||||||
|
*/
|
||||||
|
+ (NSString *)archivePath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
54
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransformer.h
generated
Normal file
54
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransformer.h
generated
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTLifecycle.h>
|
||||||
|
|
||||||
|
@class GDTEvent;
|
||||||
|
|
||||||
|
@protocol GDTEventTransformer;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** Manages the transforming of events. It's desirable for this to be its own class
|
||||||
|
* because running all events through a single instance ensures that transformers are thread-safe.
|
||||||
|
* Having a per-transport queue to run on isn't sufficient because transformer objects could
|
||||||
|
* maintain state (or at least, there's nothing to stop them from doing that) and the same instances
|
||||||
|
* may be used across multiple instances.
|
||||||
|
*/
|
||||||
|
@interface GDTTransformer : NSObject <GDTLifecycleProtocol>
|
||||||
|
|
||||||
|
/** Instantiates or returns the event transformer singleton.
|
||||||
|
*
|
||||||
|
* @return The singleton instance of the event transformer.
|
||||||
|
*/
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
/** Writes the result of applying the given transformers' -transform method on the given event.
|
||||||
|
*
|
||||||
|
* @note If the app is suspended, a background task will be created to complete work in-progress,
|
||||||
|
* but this method will not send any further events until the app is resumed.
|
||||||
|
*
|
||||||
|
* @param event The event to apply transformers on.
|
||||||
|
* @param transformers The list of transformers to apply.
|
||||||
|
*/
|
||||||
|
- (void)transformEvent:(GDTEvent *)event
|
||||||
|
withTransformers:(nullable NSArray<id<GDTEventTransformer>> *)transformers;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
36
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransformer_Private.h
generated
Normal file
36
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransformer_Private.h
generated
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTTransformer.h"
|
||||||
|
|
||||||
|
@class GDTStorage;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface GDTTransformer ()
|
||||||
|
|
||||||
|
/** The queue on which all work will occur. */
|
||||||
|
@property(nonatomic) dispatch_queue_t eventWritingQueue;
|
||||||
|
|
||||||
|
/** The storage instance used to store events. Should only be used to inject a testing fake. */
|
||||||
|
@property(nonatomic) GDTStorage *storageInstance;
|
||||||
|
|
||||||
|
/** If YES, every call to -transformEvent will result in a background task. */
|
||||||
|
@property(nonatomic, readonly) BOOL runningInBackground;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
39
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransport_Private.h
generated
Normal file
39
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTTransport_Private.h
generated
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTTransport.h>
|
||||||
|
|
||||||
|
@class GDTTransformer;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface GDTTransport ()
|
||||||
|
|
||||||
|
/** The mapping identifier that the target backend will use to map the transport bytes to proto. */
|
||||||
|
@property(nonatomic) NSString *mappingID;
|
||||||
|
|
||||||
|
/** The transformers that will operate on events sent by this transport. */
|
||||||
|
@property(nonatomic) NSArray<id<GDTEventTransformer>> *transformers;
|
||||||
|
|
||||||
|
/** The target backend of this transport. */
|
||||||
|
@property(nonatomic) NSInteger target;
|
||||||
|
|
||||||
|
/** The transformer instance to used to transform events. Allows injecting a fake during testing. */
|
||||||
|
@property(nonatomic) GDTTransformer *transformerInstance;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
80
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTUploadCoordinator.h
generated
Normal file
80
ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTLibrary/Private/GDTUploadCoordinator.h
generated
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Google
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <GoogleDataTransport/GDTLifecycle.h>
|
||||||
|
#import <GoogleDataTransport/GDTRegistrar.h>
|
||||||
|
|
||||||
|
#import "GDTLibrary/Private/GDTUploadPackage_Private.h"
|
||||||
|
|
||||||
|
@class GDTClock;
|
||||||
|
@class GDTStorage;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/** This class connects storage and uploader implementations, providing events to an uploader
|
||||||
|
* and informing the storage what events were successfully uploaded or not.
|
||||||
|
*/
|
||||||
|
@interface GDTUploadCoordinator
|
||||||
|
: NSObject <NSSecureCoding, GDTLifecycleProtocol, GDTUploadPackageProtocol>
|
||||||
|
|
||||||
|
/** The queue on which all upload coordination will occur. Also used by a dispatch timer. */
|
||||||
|
/** Creates and/or returrns the singleton.
|
||||||
|
*
|
||||||
|
* @return The singleton instance of this class.
|
||||||
|
*/
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
@property(nonatomic, readonly) dispatch_queue_t coordinationQueue;
|
||||||
|
|
||||||
|
/** A timer that will causes regular checks for events to upload. */
|
||||||
|
@property(nonatomic, readonly) dispatch_source_t timer;
|
||||||
|
|
||||||
|
/** The interval the timer will fire. */
|
||||||
|
@property(nonatomic, readonly) uint64_t timerInterval;
|
||||||
|
|
||||||
|
/** Some leeway given to libdispatch for the timer interval event. */
|
||||||
|
@property(nonatomic, readonly) uint64_t timerLeeway;
|
||||||
|
|
||||||
|
/** The map of targets to in-flight packages. */
|
||||||
|
@property(nonatomic, readonly)
|
||||||
|
NSMutableDictionary<NSNumber *, GDTUploadPackage *> *targetToInFlightPackages;
|
||||||
|
|
||||||
|
/** The storage object the coordinator will use. Generally used for testing. */
|
||||||
|
@property(nonatomic) GDTStorage *storage;
|
||||||
|
|
||||||
|
/** The registrar object the coordinator will use. Generally used for testing. */
|
||||||
|
@property(nonatomic) GDTRegistrar *registrar;
|
||||||
|
|
||||||
|
/** If YES, completion and other operations will result in serializing the singleton to disk. */
|
||||||
|
@property(nonatomic, readonly) BOOL runningInBackground;
|
||||||
|
|
||||||
|
/** Forces the backend specified by the target to upload the provided set of events. This should
|
||||||
|
* only ever happen when the QoS tier of an event requires it.
|
||||||
|
*
|
||||||
|
* @param target The target that should force an upload.
|
||||||
|
*/
|
||||||
|
- (void)forceUploadForTarget:(GDTTarget)target;
|
||||||
|
|
||||||
|
/** Starts the upload timer. */
|
||||||
|
- (void)startTimer;
|
||||||
|
|
||||||
|
/** Stops the upload timer from running. */
|
||||||
|
- (void)stopTimer;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue