The problem is:
\qrcode
does first modify the catcode-régime and then call some internal macros.
The internal macros in turn shall cause LaTeX to read from the .tex-input-file and tokenize their arguments under the modified catcode-régime.
This reading and tokenizing arguments under the modified catcode-régime is outmaneuvered when tokenizing the entire call to \qrcode
takes place under normal/non-modified catcode-régime at the time of defining the macro \contact
.
Reading from the .tex-input-file and tokenizing things under different catcode-régimes yields different sets of tokens which in turn yield different qr-codes.
A workaround for defining the macro \contact
can be reading and tokenizing the entire call to \qrcode
under verbatim-catcode-régime and passing it to \scantokens
which in turn pretends unexpanded-writing things to a text-file and reading that text-file. \scantokens
'reading-part ensures that things get re-tokenized whereby the changes of the catcode-régime performed by \qrcode
affect things.
My -eh- private toolkit for LaTeX-programming contains a macro \UDcollectverbarg
which can be used for having things tokenized under verbatim-catcode-régime before passing them as arguments to other commands:
\documentclass[border=1cm]{standalone}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Implement stuff for reading arguments "verbatim":
%
% Usually \endlinechar has the value `\^^M which implies that
% LaTeX usually does insert character 13 (return) at each line-ending.
% There are situations where this needs to be replaced by the
% newline-character (usually ^^J). (E.g., with \scantokens'
% unexpanded-writing-to-file-part...)
%
% Maybe the routine for \UDcollectverbarg could be shorter but I wanted
% both syntax |verbatim-arg| and syntax {verbatim-arg} to be possible.
%
% Syntax of \UDcollectverbarg:
%
% \UDcollectverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
% <Mandatory 1>{<Mandatory2>{<verbatim-Arg>}}
%
% Syntax of \UDconcatverbarg:
%
% \UDconcatverbarg{<^^M-replacement>}{<Mandatory 1>}{<Mandatory 2>}<verbatim-Arg>
%
% yields:
%
% <Mandatory 1>{<Mandatory2><verbatim-Arg>}
%
% with each character ^^M (usually=\endline-char) replaced by
% token-sequence <^^M-replacement>
%
% The Mandatory-Arguments are mandatory. If they consist of several
% tokens, they must be nested into catcode-1/2-character-pair / braces.
% If reading is necessary, they will be read under normal catcode-
% conditions.
% The verbatim-Arg is also mandatory. It will be read under
% verbatim-catcode-conditions. If its first character is a brace,
% it will be "assumed" that the argument is nested into braces.
% Otherwise it will be assumed, that the argument is delimited
% by the first character - like the argument of \verb.
%
% Empty-lines will not be ignored.
%
% By nesting calls to \UDcollectverbarg within \UDcollectverbarg's first
% argument, you can collect "verbatim-arguments" within its second
% argument.
%
% E.g.,
%
% \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- Mandatory 1
% {<actionB>}% <- Mandatory
% <verbatim-Arg1><verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
% \UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- Mandatory 1
% {<actionB><verbatim-Arg1>}% <- Mandatory 2
% <verbatim-Arg2><verbatim-Arg3>
%
% yields:
%
% \UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- Mandatory 1
% {<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}}% <- Mandatory 2
% <verbatim-Arg3>
%
% yields:
%
% <actionA>{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
% Assume <actionA> = \@firstofone -> equals:
%
% \@firstofone{<actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}}
%
% yields:
%
% <actionB>{<verbatim-Arg1>}{<verbatim-Arg2>}{<verbatim-Arg3>}
\newcommand\@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
\begingroup
\catcode`\^^M=12 %
\@firstoftwo{%
\endgroup%%%%
\newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
\newcommand*\@UDEndlreplace{}%
\long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
\@CheckWhetherNull{#3}%
{ #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
}%
}{}%
\newcommand\UDcollectverbarg{\@UDverbarg{\@UDcollectverbarg}}%
\newcommand\@UDverbarg[4]{%
\@bsphack
\begingroup
\let\do\@makeother\dospecials
\catcode`\{=1 %
\catcode`\ =10 %
\@ifnextchar\bgroup
{\catcode`\}=2 \@@UDverbarg{#1}{#2}{#3}{#4}{}}%
{\do\{\@@UDverbarg{#1}{#2}{#3}{#4}}%
}%
\newcommand\@@UDverbarg[5]{%
\do\ %
\catcode`\^^M=12 %
\long\def\@tempb##1#5{%
\edef\@tempb{##1}%
\@onelevel@sanitize\@tempb
\expandafter\UDEndlreplace\expandafter{\@tempb}{#2}{\def\@tempb}%
\expandafter#1\expandafter{\@tempb}{#3}{#4}%
}%
\@tempb
}%
\newcommand\@UDcollectverbarg[3]{%
\endgroup
\@esphack
#2{#3{#1}}%
}%
\makeatother
% Implementing stuff for reading arguments "verbatim" done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usepackage[]{qrcode}
\begingroup
\newlinechar=`\^^J %
\catcode`\^^J=12 %
\UDcollectverbarg{^^J}{\endgroup\newcommand{\contact}}{\scantokens}|%
\qrcode[]{
BEGIN:VCARD
VERSION:4.0
EMAIL:[email protected]
FN:John Doe
N:Doe;John;;;
TEL;TYPE=home:123456789
UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
URL:www.doe.net
END:VCARD
}%
|%
\begin{document}
\qrcode[]{
BEGIN:VCARD
VERSION:4.0
EMAIL:[email protected]
FN:John Doe
N:Doe;John;;;
TEL;TYPE=home:123456789
UID:8cbddd73-d45d-45ad-a1e4-9587984e880d
URL:www.doe.net
END:VCARD
}
\contact
\end{document}

\qrcode
command does several changes in the category code of characters and also to the endline character. These cannot be applied if\qrcode{...}
is in the argument to another command (such as\newcommand
).As with all verbatim modes, however, because T E X irrevocably sets catcodes when it first encounters characters, this will not work if the \qrcode macro is contained in another macro.
However, that comment refers to "special characters"...and I don't see them in your input.